Decimal expansion based on slot length summation - python

I'm trying to create an algorithm to produce a decimal number by certain way.
a) I have an initial number say i = 2.
b) Then I have an incremental addition method, say f(n) { n * 2 }.
c) Then I have a slot length for digits say l = 2, that creates front zeros for small numbers and limits max length of the longer numbers. 2 becomes 02, 64 is 64, but 512 = (5)12 where 5 is moved backward on previous slot
d) Max slots is the fourth parameter, m = 10
e) Finally I want to compute value by summing up digit from slots and using it as a decimal part of the 0.
So with given example:
i=2
f(n)=n*2
l=2
m=10
outcome should be produced in this manner:
step 1)
02 04 08 16 32 64 128 256 512 1024
step 2)
02 04 08 16 32 64
1 28
2 56
5 12
10 24
->
slot: 1 2 3 4 5 6 7 8 9 10
computed: 02 04 08 16 32 65 30 61 22 24
step 3)
I have a number: 02040816326530612224 or 0.02040816326530612224 as stated on part e).
Note that if max slot is bigger in this example, then numbers on slots 9 and 10 will change. I also want to have part b) as a function, so I can change it to other like fib(nx) {n1+n2}.
I prefer Python as a computer language for algo, but anything that is easy to transform to Python is acceptable.
ADDED
This is a function I have managed to create so far:
# l = slot length, doesnt work with number > 2...
def comp(l = 2):
a = []
# how to pass a function, that produces this list?
b = [[0, 2], [0, 4], [0, 8], [1, 6], [3, 2], [6, 4], [1, 2, 8], [2, 5, 6], [5, 1, 2], [1, 0, 2, 4], [2, 0, 4, 8]]
r = 0
# main algo
for bb in b:
ll = len(bb)
for i in range(0, ll):
x = r + i - ll + l
# is there a better way to do following try except part?
try:
a[x] += bb[i]
except IndexError:
a.append(bb[i])
# moving bits backward, any better way to do this?
s = a[x] - 9
d = 0
while s > 0:
d += 1
a[x] -= 10
a[x-d] += 1
s = a[x-d] - 9
r += l
return '0.' + ''.join(map(str, a))

def doub(n):
return pow(2, n)
def fibo(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
def fixed_slot_numbers(f, l, m):
b = []
for n in range(1, m):
a = [int(c) for c in str(f(n))]
while len(a) < l:
a.insert(0, 0)
b.append(a)
return b
def algo(function, fixed_slot_length = 2, max_slots = 12):
a = []
slot_numbers = fixed_slot_numbers(function, fixed_slot_length, max_slots)
for r, b in enumerate(slot_numbers):
r *= fixed_slot_length
slot_length = len(b)
for bidx in range(0, slot_length):
aidx = r + bidx - slot_length + fixed_slot_length
try:
a[aidx] += b[bidx]
except IndexError:
a.append(b[bidx])
d = 0
while a[aidx-d] > 9:
a[aidx-d] -= 10
d += 1
a[aidx-d] += 1
return '0.%s' % ''.join(map(str, a))
algo(doub, 2, 28) -> 0.020408163265306122448979591836734693877551020405424128 = 1/49
algo(fibo, 1, 28) -> 0.112359550561797752808950848 = 10/89

Related

Group a numpy array

I have an one-dimensional array A, such that 0 <= A[i] <= 11, and I want to map A to an array B such that
for i in range(len(A)):
if 0 <= A[i] <= 2: B[i] = 0
elif 3 <= A[i] <= 5: B[i] = 1
elif 6 <= A[i] <= 8: B[i] = 2
elif 9 <= A[i] <= 11: B[i] = 3
How can implement this efficiently in numpy?
You need to use an int division by //3, and that is the most performant solution
A = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
B = A // 3
print(A) # [0 1 2 3 4 5 6 7 8 9 10 11]
print(B) # [0 0 0 1 1 1 2 2 2 3 3 3]
I would do something like dividing the values of the A[i] by 3 'cause you're sorting out them 3 by 3, 0-2 divided by 3 go answer 0, 3-5 go answer 1, 6-8 divided by 3 is equal to 2, and so on
I built a little schema here:
A[i] --> 0-2. divided by 3 = 0, what you wnat in array B[i] is 0, so it's ok
A[i] --> 3-5. divided by 3 = 1, and so on. Just use a method to make floor the value, so that it don't become float type.
Answers provided by others are valid, however I find this function from numpy quite elegant, plus it allows you to avoid for loop which could be quite inefficient for large arrays
import numpy as np
bins = [3, 5, 8, 9, 11]
B = np.digitize(A, bins)
Something like this might work:
C = np.zeros(12, dtype=np.int)
C[3:6] = 1
C[6:9] = 2
C[9:12] = 3
B = C[A]
If you hope to expand this to a more complex example you can define a function with all your conditions:
def f(a):
if 0 <= a and a <= 2:
return 0
elif 3 <= a and a <= 5:
return 1
elif 6 <= a and a <= 8:
return 2
elif 9 <= a and a <= 11:
return 3
And call it on your array A:
A = np.array([0,1,5,7,8,9,10,10, 11])
B = np.array(list(map(f, A))) # array([0, 0, 1, 2, 2, 3, 3, 3, 3])

Iterative summation

I'm trying to write a python code that allows me to iteratively sum up the average values of three elements of a list, starting with the third element and its two predecessors. Let me give you an example:
list = [1, 2, 3, 4, 5, 6, 7]
I want to calculate the following:
sum_of_average_values = sum(1, 2, 3)/3 + sum(2, 3, 4)/3 + sum(3, 4, 5)/3 + sum(4, 5, 6)/3 + sum(5, 6, 7)/3
Since I'm quite new to programming I couldn't find an effective way of putting this into a function.
You can do in this way:
a = [1,2,3,4,5,6,7]
sum_of_average_values = 0
for i in range(0,len(a)-2):
sum_of_average_values += sum(a[i:i+2])/3
print(sum_of_average_values)
You could use rolling from pandas.
import pandas as pd
num_list = [1, 2, 3, 4, 5, 6, 7]
average_sum = sum(pd.Series(num_list).rolling(3).mean().dropna())
print(average_sum)
Many ways to achieve this, one way is recursively.
The function averages the last three elements of a list and adds the result to the result generated by the function with a list lacking the last element. Continues like this until the list is shorter than 3.
def fn(l):
if len(l) < 3:
return 0
return sum(l[-3:])/3 + fn(l[:-1])
print(fn([1, 2, 3, 4, 5, 6, 7]))
Another solution where you can specify the amount of elements you want to sum up and average:
l = [1, 2, 3, 4, 5, 6, 7]
def sum_avg(l, n):
res = 0
for i in range(n-1, len(l)):
res += sum([l[j] for j in range(i, i-n, -1)])/n
return res
print(sum_avg(l, 3))
--> 20.0
Mathematically, this would could be obtain by averaging the sums of 3 sublists:
L = [1, 2, 3, 4, 5, 6, 7]
r = (sum(L) + sum(L[1:-1]) + sum(L[2:-2]))/3 # 20.0
and can be generalized to a window size of w:
w = 3
r = sum(sum(L[p:-p or None]) for p in range(w)) / w
It can also be implemented without the overhead of generating sublists by using item positions to determine the number of times they are added to the total:
r = sum(n*min(i+1,len(L)-i,w) for i,n in enumerate(L)) / w
This would be the most memory-efficient of the 3 methods because it use an iterator to feed data to the sum function and only goes through the data once.
Detailed explanation:
Since all the averages that are added together are a division by 3, we can produce the total sum and divide by 3 at the end
the number at the first and last positions are added once
the number at the second and penultimate positions are added twice
The numbers from the third position up to the antepenultimate will be added 3 times
visually:
(1 + 2 + 3) / 3
(2 + 3 + 4) / 3
(3 + 4 + 5) / 3
(4 + 5 + 6) / 3
(5 + 6 + 7) / 3
(1x1 + 2x2 + 3x3 + 4x3 + 5x3 + 6x2 + 7x1) / 3 = 20.0
n = 1 2 3 4 5 6 7 # value
* = 1 2 3 3 3 2 1 # multiplier (times added)
-------------------------
(2, 4, 9, 12, 15, 12, 7) / 3 = 20.0
i = 0 1 2 3 4 5 6 # index
1 2 3 3 3 2 1 # min(i+1,len(L)-i,w) = multiplier
You can do in one line using list comprehension as:
n = 3
avg = sum( [ sum(lst[i:i+n])/n for i in range(0, len(lst) - (n - 1)) ] )
print(avg) # 20.0

How to find sum of product of min value and length of sub list

I have a list of n numbers. I want to divide the list into sub lists, such as the sub list consists of continuous increasing numbers or continuous decreasing numbers. Then take the product of each sub list's min value and it's length. Finally take the sum of all this product's
Input:
l = [1,2,6,4,2,3,1,8,9,7]
Output:
32
Details:
[1,2,6],[6,4,2],[2,3],[3,1],[1,8,9],[9,7]
(1*3) +(2*3) + (2*2)+(1*2)+(1*3)+ (7*2) = 32
Code so far:
n = 10
l = [1,2,6,4,2,3,1,8,9,7]
tot = 0
count = 0
inc=dec=False
min_val = 1001 # max value in list won't exceed 1000
for idx, e in enumerate(l):
if idx+1<=n:
if e > l[idx+1]:
count+=1
if min_val > l[idx+1]:
min_val=l[idx+1]
inc=True
dec=False
elif e < l[idx+1]:
count+=1
if min_val > e:
min_val=e
dec=True
# if not inc
inc=False
*Note: No Two adjacent value will be equal in the list.
Update-1:
itemp = [1001]
dtemp = [1001]
result=0
for e in l:
# if not itemp or not dtemp:
# itemp.append(e)
# dtemp.append(e)
if e > itemp[-1]:
if not dtemp:
itemp.append(e)
else:
result+=(min(dtemp)*(len(dtemp)-1))
dtemp=[1001]
itemp.append(e)
elif e < dtemp[-1]:
dtemp.append(e)
if not itemp:
dtemp.append(e)
else:
result+=(min(itemp)*(len(itemp)-1))
itemp=[1001]
dtemp.append(e)
print(result)
This results 0 as output. Can some one help?
l = [1,2,6,4,2,3,1,8,9,7]
local_max= [i for i in range(1, len(l)-1) if l[i-1]<l[i]>l[i+1]]
local_min= [i for i in range(1, len(l)-1) if l[i-1]>l[i]<l[i+1]]
idx= sorted(local_max+local_min +[0,len(l)-1])
idx_pairs = zip(idx[:-1],idx[1:])
sum(min(l[i_1],l[i_2])*(i_2+1-i_1) for i_1,i_2 in idx_pairs)
You could identify the breaking positions (peaks and bottoms) using zip to detect changes of increasing/decreasing values between each sequence of 3 elements. Then use these breaks to form the sub-lists and apply the calculation in a comprehension.
L = [1,2,6,4,2,3,1,8,9,7]
breaks = [i+1 for i,(a,b,c) in enumerate(zip(L,L[1:],L[2:])) if (a<b)==(b>c)]
subL = [ L[s:e+1] for s,e in zip([0]+breaks,breaks+[len(L)]) ]
result = sum(min(s)*len(s) for s in subL)
print(breaks) # [2, 4, 5, 6, 8] indices of peaks and bottoms
# [1,2,6,4,2,3,1,8,9,7]
# ^ ^ ^ ^ ^
# 0 1 2 3 4 5 6 7 8 9
print(subL) # [ [1, 2, 6], [6, 4, 2], [2, 3], [3, 1], [1, 8, 9], [9, 7]]
# 0..2+1 2..4+1 4..5+1 5..6+1 6..8+1 8..len(L)
# | | | | | | | | | | | |
# [0] | + [2, | 4, | 5, | 6, | 8] |
# [2, 4, 5, 6, 8] + [len(L)]
print(result) # 32
tot = start = m = n = 0
direc = -1
for n, x in enumerate(lis):
if n == 0:
m = x
else:
old = lis[n - 1]
if (x > old and direc == 0) or (x < old and direc == 1):
tot += m * (n - start)
start = n - 1
m = min(old, x)
direc ^= 1
else:
direc = 1 if x > old else 0
m = min(m, x)
ln = n - start + 1
if ln > 1:
tot += m * ln

How to get all the diagonal two-dimensional list without using numpy?

We have:
a = [[1, 2, 4], [-1, 3, 4], [9, -3, 7]]
Diagonal traversal as a list:
[1, -1, 2, 9, 3, 4]
n = int(input())
a = [[0]*n for _ in range(n)]
for i in range(n):
a[i] = [int(j) for j in input().strip().split(" ")]
res = []
for j in range(n):
for k in range(j + 1):
res.append(a[j - k][k])
print(res)
How do I get the remaining two diagonals?
I need to get:
[-3, 4, 7]
Try this. Define variables COL and ROW and then run the following function with your matrix.
def diagonalOrder(matrix) :     
    # There will be ROW+COL-1 lines in the output
    for line in range(1, (ROW + COL)) :
        # Get column index of the first element
        # in this line of output. The index is 0
        # for first ROW lines and line - ROW for
        # remaining lines 
        start_col = max(0, line - ROW)
        # Get count of elements in this line.
        # The count of elements is equal to
        # minimum of line number, COL-start_col and ROW 
        count = min(line, (COL - start_col), ROW)
        # Print elements of this line 
        for j in range(0, count) :
            print(matrix[min(ROW, line) - j - 1]
                        [start_col + j], end = "\t")
        print()
First, see this 3x3 matrix with each element containing its row in the first digit and its column in the second digit.
00 01 02
10 11 12
20 21 22
The elements that you want are in the order:
00 10 01 20 11 02 21 12 22
Or in other perspective:
00
10 01
20 11 02
21 12
22
You can see that, in the first column of the numbers above, the first digits are 01222. This represents range(3) + [2, 2]. Now, look at the second digits of the first column. They are 00012 and represents [0, 0] + range(3).
Also, note that, in each row, each element decreases its first digit and increases its second digit until the element is equal to its inverse. You can see it more clearly in the third row. It starts at 20, goes to 11 and stop at 02, which is the inverse of 20, the initial number.
So, you can do something like:
def toNumber(i, j):
return int(str(i) + str(j))
res = []
a = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
list1 = list(range(3)) + [2]*2
list2 = [0]*2 + list(range(3))
for i, j in zip(list1, list2):
inverse = int(str(toNumber(i, j))[::-1])
while True:
res.append(a[i][j])
if toNumber(i, j) == inverse:
break
i -= 1
j += 1
print(res)

creating a spiral array in python?

Me and my mate were trying to create a fun game in python where the elements entered in the array are accessed in a spiral manner. I have tried few methods like one given below (source).
def spiral(X, Y):
x = y = 0
dx = 0
dy = -1
for i in range(max(X, Y)**2):
if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
print (x, y)
# DO STUFF...
if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y):
dx, dy = -dy, dx
x, y = x+dx, y+dy
The above statement accesses the elements in spiral loop and prints them for a defined array AE. I would like to know how can I transform a given array AE to a spiral one
You can build a spiral by starting near the center of the matrix and always turning right unless the element has been visited already:
#!/usr/bin/env python
NORTH, S, W, E = (0, -1), (0, 1), (-1, 0), (1, 0) # directions
turn_right = {NORTH: E, E: S, S: W, W: NORTH} # old -> new direction
def spiral(width, height):
if width < 1 or height < 1:
raise ValueError
x, y = width // 2, height // 2 # start near the center
dx, dy = NORTH # initial direction
matrix = [[None] * width for _ in range(height)]
count = 0
while True:
count += 1
matrix[y][x] = count # visit
# try to turn right
new_dx, new_dy = turn_right[dx,dy]
new_x, new_y = x + new_dx, y + new_dy
if (0 <= new_x < width and 0 <= new_y < height and
matrix[new_y][new_x] is None): # can turn right
x, y = new_x, new_y
dx, dy = new_dx, new_dy
else: # try to move straight
x, y = x + dx, y + dy
if not (0 <= x < width and 0 <= y < height):
return matrix # nowhere to go
def print_matrix(matrix):
width = len(str(max(el for row in matrix for el in row if el is not None)))
fmt = "{:0%dd}" % width
for row in matrix:
print(" ".join("_"*width if el is None else fmt.format(el) for el in row))
Example:
>>> print_matrix(spiral(5, 5))
21 22 23 24 25
20 07 08 09 10
19 06 01 02 11
18 05 04 03 12
17 16 15 14 13
Introductory remarks
The question is closely related to a problem of printing an array in spiral order. In fact, if we already have a function which does it, then the problem in question is relatively simple.
There is a multitude of resources on how to produce a spiral matrix or how to loop or print an array in spiral order. Even so, I decided to write my own version, using numpy arrays. The idea is not original but use of numpy makes the code more concise.
The other reason is that most of examples of producing a spiral matrix I found (including the code in the question and in the other answers) deal only with square matrices of size n x n for odd n. Finding the start (or end) point in matrices of other sizes may be tricky. For example, for a 3x5 matrix it can't be the middle cell. The code below is general and the position of the starting (ending) point depends on the choice of the function spiral_xxx.
Code
The first function unwraps an array in spiral order clockwise:
import numpy as np
def spiral_cw(A):
A = np.array(A)
out = []
while(A.size):
out.append(A[0]) # take first row
A = A[1:].T[::-1] # cut off first row and rotate counterclockwise
return np.concatenate(out)
We can write this function on eight different ways depending on where we start and how we rotate the matrix. I'll give another one, which is consistent (it will be evident later) with the matrix transformation in the image in the question. So, further on, I will be using this version:
def spiral_ccw(A):
A = np.array(A)
out = []
while(A.size):
out.append(A[0][::-1]) # first row reversed
A = A[1:][::-1].T # cut off first row and rotate clockwise
return np.concatenate(out)
How it works:
A = np.arange(15).reshape(3,5)
print(A)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
print(spiral_ccw(A))
[ 4 3 2 1 0 5 10 11 12 13 14 9 8 7 6]
Note that the end (or start) point is not the middle cell. This function works for all type of matrices but we will need a helper function that generates spiral indices:
def base_spiral(nrow, ncol):
return spiral_ccw(np.arange(nrow*ncol).reshape(nrow,ncol))[::-1]
For example:
print(base_spiral(3,5))
[ 6 7 8 9 14 13 12 11 10 5 0 1 2 3 4]
Now come the two main functions. One transforms a matrix to a spiral form of the same dimensions, the other reverts the transformation:
def to_spiral(A):
A = np.array(A)
B = np.empty_like(A)
B.flat[base_spiral(*A.shape)] = A.flat
return B
def from_spiral(A):
A = np.array(A)
return A.flat[base_spiral(*A.shape)].reshape(A.shape)
Examples
Matrix 3 x 5:
A = np.arange(15).reshape(3,5)
print(A)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
print(to_spiral(A))
[[10 11 12 13 14]
[ 9 0 1 2 3]
[ 8 7 6 5 4]]
print(from_spiral(to_spiral(A)))
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
Matrix from the question:
B = np.arange(1,26).reshape(5,5)
print(B)
[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]]
print(to_spiral(B))
[[21 22 23 24 25]
[20 7 8 9 10]
[19 6 1 2 11]
[18 5 4 3 12]
[17 16 15 14 13]]
print(from_spiral(to_spiral(B)))
[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]]
Remark
If you are going to work only with fixed size matrices, for example 5x5, then it's worth replacing base_spiral(*A.shape) in definitions of the functions with a fixed matrix of indices, say Ind (where Ind = base_spiral(5,5)).
Below is python3 code which transforms:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]]
to
[[20, 19, 18, 17, 16],
[21, 6, 5, 4, 15],
[22, 7, 0, 3, 14],
[23, 8, 1, 2, 13],
[24, 9, 10, 11, 12]]
You can easily change implementation in such way how do you want...
def spiral(X, Y):
x = y = 0
dx = 0
dy = -1
for i in range(max(X, Y) ** 2):
if (-X / 2 < x <= X / 2) and (-Y / 2 < y <= Y / 2):
yield x, y
# print(x, y)
# DO STUFF...
if x == y or (x < 0 and x == -y) or (x > 0 and x == 1 - y):
dx, dy = -dy, dx
x, y = x + dx, y + dy
spiral_matrix_size = 5
my_list = list(range(spiral_matrix_size**2))
my_list = [my_list[x:x + spiral_matrix_size] for x in range(0, len(my_list), spiral_matrix_size)]
print(my_list)
for i, (x, y) in enumerate(spiral(spiral_matrix_size, spiral_matrix_size)):
diff = int(spiral_matrix_size / 2)
my_list[x + diff][y + diff] = i
print(my_list)
Here's a solution using itertools and virtually no maths, just observations about what the spiral looks like. I think it's elegant and pretty easy to understand.
from math import ceil, sqrt
from itertools import cycle, count, izip
def spiral_distances():
"""
Yields 1, 1, 2, 2, 3, 3, ...
"""
for distance in count(1):
for _ in (0, 1):
yield distance
def clockwise_directions():
"""
Yields right, down, left, up, right, down, left, up, right, ...
"""
left = (-1, 0)
right = (1, 0)
up = (0, -1)
down = (0, 1)
return cycle((right, down, left, up))
def spiral_movements():
"""
Yields each individual movement to make a spiral:
right, down, left, left, up, up, right, right, right, down, down, down, ...
"""
for distance, direction in izip(spiral_distances(), clockwise_directions()):
for _ in range(distance):
yield direction
def square(width):
"""
Returns a width x width 2D list filled with Nones
"""
return [[None] * width for _ in range(width)]
def spiral(inp):
width = int(ceil(sqrt(len(inp))))
result = square(width)
x = width // 2
y = width // 2
for value, movement in izip(inp, spiral_movements()):
result[y][x] = value
dx, dy = movement
x += dx
y += dy
return result
Usage:
from pprint import pprint
pprint(spiral(range(1, 26)))
Output:
[[21, 22, 23, 24, 25],
[20, 7, 8, 9, 10],
[19, 6, 1, 2, 11],
[18, 5, 4, 3, 12],
[17, 16, 15, 14, 13]]
Here's the same solution shortened:
def stretch(items, counts):
for item, count in izip(items, counts):
for _ in range(count):
yield item
def spiral(inp):
width = int(ceil(sqrt(len(inp))))
result = [[None] * width for _ in range(width)]
x = width // 2
y = width // 2
for value, (dx, dy) in izip(inp,
stretch(cycle([(1, 0), (0, 1), (-1, 0), (0, -1)]),
stretch(count(1),
repeat(2)))):
result[y][x] = value
x += dx
y += dy
return result
I've ignored the fact that you want the input to be a 2D array since it makes much more sense for it to be any 1D iterable. You can easily flatten the input 2D array if you want. I've also assumed the output should be a square since I can't think what you'd sensibly want otherwise. It may go over the edge and raise an error if the square has even length and the input is too long: again, I don't know what the alternative would be.
You can fill an array with somehing like this :
#!/usr/bin/python
class filler:
def __init__(self, srcarray):
self.size = len(srcarray)
self.array = [[None for y in range(self.size)] for y in range(self.size)]
self.xpos, self.ypos = 0, 0
self.directions = [self.down, self.right, self.up, self.left]
self.direction = 0
self.fill(srcarray)
def fill(self, srcarray):
for row in reversed(srcarray):
for elem in reversed(row):
self.array[self.xpos][self.ypos] = elem
self.go_to_next()
def check_next_pos(self):
np = self.get_next_pos()
if np[1] in range(self.size) and np[0] in range(self.size):
return self.array[np[0]][np[1]] == None
return False
def go_to_next(self):
i = 0
while not self.check_next_pos() and i < 4:
self.direction = (self.direction + 1) % 4
i += 4
self.xpos, self.ypos = self.get_next_pos()
def get_next_pos(self):
return self.directions[self.direction](self.xpos, self.ypos)
def down(self, x, y):
return x + 1, y
def right(self, x, y):
return x, y + 1
def up(self, x, y):
return x - 1, y
def left(self, x, y):
return x, y - 1
def print_grid(self):
for row in self.array:
print(row)
f = filler([[x+y*5 for x in range(5)] for y in range(5)])
f.print_grid()
The output of this will be :
[24, 9, 10, 11, 12]
[23, 8, 1, 2, 13]
[22, 7, 0, 3, 14]
[21, 6, 5, 4, 15]
[20, 19, 18, 17, 16]
def counter(n):
for i in range(1,n*n):
yield i+1
n = 11
a = [[1 for x in range(n)] for y in range(n)]
x = y = n//2
val = counter(n)
for i in range(2, n, 2):
y += 1
x -= 1
for k in range(i):
x += 1
a[x][y] = next(val)
for k in range(i):
y -= 1
a[x][y] = next(val)
for k in range(i):
x -= 1
a[x][y] = next(val)
for k in range(i):
y += 1
a[x][y] = next(val)
for i in range(n):
for j in range(n):
print (a[i][j] , end="")
print (" " , end="")
print("\n")
I'm just doing something about generating various spiral indexing of a array and I add some simple modifications to the answer of ptrj to make the function more general. The modified function supports beginning the indexing from the four corners with clockwise and counter-clockwise directions.
def spiral_ind(A,start,direction):
if direction == 'cw':
if start == 'right top':
A = np.rot90(A)
elif start == 'left bottom':
A = np.rot90(A,k=3)
elif start == 'right bottom':
A = np.rot90(A,k=2)
elif direction == 'ccw':
if start == 'left top':
A = np.rot90(A,k=3)
elif start == 'left bottom':
A = np.rot90(A,k=2)
elif start == 'right bottom':
A = np.rot90(A)
out = []
while(A.size):
if direction == 'cw':
out.append(A[0])
A = A[1:].T[::-1]
elif direction == 'ccw':
out.append(A[0][::-1])
A = A[1:][::-1].T
return np.concatenate(out)
def spiral(m):
a=[]
t=list(zip(*m)) # you get the columns by zip function
while m!=[]:
if m==[]:
break
m=list(zip(*t)) # zip t will give you same m matrix. It is necessary for iteration
a.extend(m.pop(0)) # Step1 : pop first row
if m==[]:
break
t=list(zip(*m))
a.extend(t.pop(-1)) # Step 2: pop last column
if m==[]:
break
m=list(zip(*t))
a.extend(m.pop(-1)[::-1]) # Step 3: pop last row in reverse order
if m==[]:
break
t=list(zip(*m))
a.extend(t.pop(0)[::-1]) # Step 4: pop first column in reverse order
return a
This solution is O(n); just one while loop; much faster and can be used for much bigger dimensions of matrices
I had a related problem: I have two digital elevation models that might not be exactly aligned. To check how many cells they're miss-aligned by, I wanted a list of (x,y) offset tuples, starting with the smallest offsets first. I solved the problem by coding a spiral walk that creates square spirals of any size. It can travel either clockwise or counterclockwise. Commented code is below. Similar idea to some of the other solutions, but commented and with a bit less repeated code.
#Generates a list of offsets to check starting with the smallest offsets
#first. Seed the list with (0,0)
to_check = [(0,0)]
#Current index of the "walker"
cur_ind = np.array([0,0])
#Direction to start move along the sides
move_step = 1
#Controls the direction of the spiral
#any odd integer = counter clockwise
#any even integer = clockwise
ctr = 0
#The size of each side of the spiral to be created
size = 5
#Iterate the through the number of steps to take along each side
for i in range(1,size+1):
#Toggle the direction of movement along the sides
move_step *= -1
#Step along each of the two sides that has the same number of
#elements
for _ in range(2):
#Increment the counter (changes whether the x or y index in
#cur_ind is incremented)
ctr += 1
for ii in range(i):
#Move the "walker" in the direction indicated by move_step
#along the side indicated
cur_ind[ctr%2] += move_step
#Add the current location of the water to the list of index
#tuples
to_check.append((cur_ind[0],cur_ind[1]))
#Truncate the list to just the indices to create the spiral size
#requested
to_check = to_check[:size**2]
#Check that the spiral is working
#Create an empty array
arr = np.zeros([size,size])*np.nan
ctr = 1
#for each x,y offset pair:
for dx,dy in to_check:
#Starting at the approximate center of the array, place the ctr
#at the index indicated by the offset
arr[int(size/2)+dx,int(size/2)+dy]=ctr
ctr+=1
print(arr)
The last few lines just display the spiral:
[[13. 14. 15. 16. 17.]
[12. 3. 4. 5. 18.]
[11. 2. 1. 6. 19.]
[10. 9. 8. 7. 20.]
[25. 24. 23. 22. 21.]]

Categories

Resources