How to resample an array by duplicating/skipping every N item? - python

I am confused on how to achieve the following:
Say I have an array of size X (e.g: 3000 items). I want to create a function that will stretch that array to size Y (e.g: 4000) by duplicating every N item.
Along with another function to do the opposite, remove every N items to make the array size 2000 for example.
I guess this is more of a math problem than a programming problem, and as you can tell maths aren't my strong point. Here's what I have so far:
def upsample(originalArray, targetSize):
newArray = []
j = 0
for i in range (0, len(originalArray)):
newArray.append(originalArray[i])
# calculate at what interval items need to be duplicated
# this is what I'm having trouble with
if j == interval:
newArray.append(originalArray[i])
j = 0
j+=1
return newArray
Here is an example of what I'm trying to do:
# stretch array from 10 to 12 items
originalArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
upsample(originalArray, 11)
# output: [0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9]
Any help will be much appreciated

Create a floating point linspace and map it back to integer to use it as indices for your original Array. (Since you wanted [0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9] instead of [0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9] you need to do this flipping stuff in the if condition).
The code avoids loops for performance.
import numpy as np
def upsample(originalArray, targetSize):
x = np.linspace(0, originalArray.size, num=targetSize, endpoint=False)
if targetSize > originalArray.size:
x = -np.flip(x, axis=0) + originalArray.size
x[-1] = originalArray.size - 1
x = originalArray[x.astype(int)]
return x
upsample(originalArray, 21) gives [0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 9]
upsample(originalArray, 23) gives [0 0 1 1 2 2 3 3 3 4 4 5 5 6 6 6 7 7 8 8 9 9 9]
upsample(originalArray, 5) gives [0 2 4 6 8]
etc.

To downsample your array:
N =2 #downsampling by 2
new = originalArray[0:N:]
To upsample (a being originaArray):
new = [item for t in [[a[i]]*2 if i%N==0 else [a[i],] for i in range(0,len(a))] for item in t]
or more explicitly:
res = list()
i=0
while(i<len(originalArray)):
res.append(originalArray[i])
if i%N==0:
continue
i +=1

Related

Maze algorithm python

Turn the four rings so that the sums of each four of the numbers that are located along the same radius are the same. Find what they are equal to?
problem image
We can do it by Brute Force method but it will be dummy cause too many combinations.
I had thoughts about DFS method but cant imagine how to consume it here truly.
I dont need code for this problem, perhaps you can share your thoughts on this issue.
input data
1-st ring: 3 9 6 4 3 7 5 2 4 8 3 6
2-nd ring: 8 4 7 5 8 2 9 5 5 8 4 6
3-rd ring: 6 5 8 1 6 6 7 1 3 7 1 9
4-th ring: 9 2 4 6 8 4 3 8 5 2 3 7
Have done this problem without using any theoretical algorithm using python.
Just simple Brute Force method like walking through my rings starting from 2-nd one**
def find_radius(*args):
arr = []
for i in range(0, len(args[0])):
sum_radius = args[0][i] + args[1][i] + args[2][i] + args[3][i]
arr.append(sum_radius)
return list(dict.fromkeys(arr))
def move_ring(arr):
first_element = arr[0]
arr.remove(first_element)
arr.append(first_element)
return arr
def print_all_rings(*args):
print(args[0])
print(args[1])
print(args[2])
print(args[3])
if __name__ == '__main__':
# first example
ring_1 = [3, 9, 6, 4, 3, 7, 5, 2, 4, 8, 3, 6]
ring_2 = [8, 4, 7, 5, 8, 2, 9, 5, 5, 8, 4, 6]
ring_3 = [6, 5, 8, 1, 6, 6, 7, 1, 3, 7, 1, 9]
ring_4 = [9, 2, 4, 6, 8, 4, 3, 8, 5, 2, 3, 7]
# second example
# ring_1 = [4, 2]
# ring_2 = [6, 8]
# ring_3 = [9, 8]
# ring_4 = [5, 8]
first_round = 0
second_round = 0
while True:
if first_round == len(ring_1):
first_round = 0
move_ring(ring_3)
second_round += 1
if second_round == len(ring_1):
second_round = 0
move_ring(ring_4)
if len(find_radius(ring_1, ring_2, ring_3, ring_4)) == 1:
print("200 OK! All subsums in column are the same")
break
else:
print("404 Error!")
move_ring(ring_2)
first_round += 1
print(find_radius(ring_1, ring_2, ring_3, ring_4))
print_all_rings(ring_1, ring_2, ring_3, ring_4)
Not sure if this is what you mean by brute force, but I don't think you can avoid trying all combinations (which is exactly what a tree search does as well).
Note though that since only relative displacements matter, it is enough to search on displacements of 3 rings. You can do so using backtracking (which exactly corresponds to a tree search).

function to print all elements inside a list into a rectangle

Lets say I have a list:
li = [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]
I need to make a rectangle with dimension 5*4 with all elements inside the list. Which should output (output is plain string, not list):
1 2 3 4 5
6 7 8 9 10
1 2 3 4 5
6 7 8 9 10
How to do this? Beside that, I need to find the general formula that would allow me to create a rectangle of length*width dimension that can take input from list of any length.
Here is a working code:
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
width = 5
length = len(li)//width
for i in range(length):
print(li[i*width:width*(i+1)])
I did like this:
def list_rect(li,dim1,dim2):
i=0
for line in range(dim2):
for col in range(dim1):
if i<len(li):
print(li[i],end=' ')
i+=1
else:
i=0
print(li[i],end=' ')
print()

How do I get the diagonal elements of a matrix/grid from a specific element?

I have an 8x8 grid of different numbers, and I want to get the elements of the diagonal that contains a given starting position. Here is an example
l = [[str(randint(1,9)) for i in range(8)] for n in range(8)]
>> [
[1 5 2 8 6 9 6 8]
[2 2 2 2 8 2 2 1]
[9 5 9 6 8 2 7 2]
[2 8 8 6 4 1 8 1]
[2 5 5 5 4 4 7 9]
[3 9 8 8 9 4 1 1]
[8 9 2 4 2 8 4 3]
[4 4 7 8 7 5 3 6]
]
How would I go about getting the diagonal from the position x=4 and y=3 (so 4th list and 5th element in that list)? So The diagonal I would want would be [5,2,6,4,4,1,3].
You can calculate the row and column of the top-left item of the diagonal based on the difference of x and y, and the number of iterations based on the difference between the lower of the two boundaries and the higher of the starting row and column:
def diagonal(m, x, y):
row = max((y - x, 0))
col = max((x - y, 0))
for i in range(min((len(m), len(m[0]))) - max((row, col))):
yield m[row + i][col + i]
so that:
m = [
[1, 5, 2, 8, 6, 9, 6, 8],
[2, 2, 2, 2, 8, 2, 2, 1],
[9, 5, 9, 6, 8, 2, 7, 2],
[2, 8, 8, 6, 4, 1, 8, 1],
[2, 5, 5, 5, 4, 4, 7, 9],
[3, 9, 8, 8, 9, 4, 1, 1],
[8, 9, 2, 4, 2, 8, 4, 3],
[4, 4, 7, 8, 7, 5, 3, 6],
]
print(list(diagonal(m, 4, 3)))
outputs:
[5, 2, 6, 4, 4, 1, 3]
Here is what I came up with. It's not beautiful but it gets the job done.
def get_diagonal(full_grid, y, x):
if x > y:
while y >= 1:
x -= 1
y -= 1
else:
while x >= 1:
x -= 1
y -= 1
diagonal = []
while x < len(grid) and y < len(grid[0]):
diagonal.append(grid[x][y])
x += 1
y += 1
return diagonal
grid = [
[1, 5, 2, 8, 6, 9, 6, 8],
[2, 2, 2, 2, 8, 2, 2, 1],
[9, 5, 9, 6, 8, 2, 7, 2],
[2, 8, 8, 6, 4, 1, 8, 1],
[2, 5, 5, 5, 4, 4, 7, 9],
[3, 9, 8, 8, 9, 4, 1, 1],
[8, 9, 2, 4, 2, 8, 4, 3],
[4, 4, 7, 8, 7, 5, 3, 6]]
get_diagonal(grid, 5, 3)
It seems counter-intuitive to me to use "y" along the row and "x" along the vertical, so I've swapped them. If you're OK with starting the indexing at zero, then this worked for me:
from random import randint
l = [[str(randint(1,9)) for i in range(8)] for n in range(8)]
# Show the grid
for row in l:
print(' '.join([str(n) for n in row]))
# Give the initial position, then follow the diagonal down and
# to the right until you run out of rows or columns.
x_pos = 1
y_pos = 3
diag = []
while x_pos < len(l[0]) and y_pos < len(l):
diag.append(l[y_pos][x_pos])
x_pos += 1
y_pos += 1
print(diag)
Sample output:
1 3 8 7 3 1 5 2
4 5 8 6 9 4 3 2
2 6 1 3 8 6 8 1
7 1 8 2 7 4 7 4
9 5 5 5 5 2 3 1
8 5 9 7 2 7 1 8
3 3 3 4 2 9 8 3
3 2 8 6 2 4 4 8
['1', '5', '7', '2', '4']
From #blhsing answer, I think the number iterations should be min(len(m) - 1 - row, len(m[0]) - 1 - col) instead.
Let's see an example:
Imagine a matrix with 2 rows:
[
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
]
Let's say the starting point is the first row, element number four, if we use the original calculation (which is min((len(m), len(m[0]))) - max((row, col))) we'll end-up with (min(2,5) - max(0, 3)) = 2 - 3 = -1.
If we use the proposed one (which is min(len(m) - 1 - row, len(m[0]) - 1 - col)), we'll have min(2 - 1 - 0, 5 - 1 - 3) = min(1, 1) = 1.

Android pattern plotting in Python

I need to make make an android pattern or just a pattern in a 3x3 matrix. The pattern is [8, 7, 6, 5, 4, 3, 2, 0, 1] and I need to plot it in a 3x3 matrix. The first entry in the pattern is the beginning point and it connects to the second in the row. The result needs to be the following:
8, 9, 7
6, 5, 4
3, 2, 1
pattern = [8, 7, 6, 5, 4, 3, 2, 0, 1]
matrix = [0,0,0,0,0,0,0,0,0]
lst = ([matrix[i:i + 3] for i in range(0, len(matrix), 3)])
for i in lst:
print(i)
for char in pattern:
matrix[char]=char
Do you mean something like this:
def print_pattern(pattern, cols=3):
for ii, pp in enumerate(pattern):
if ii % cols == 0:
print("")
print(pp),
Then you can call this function as
pattern = [8, 7, 6, 5, 4, 3, 2, 0, 1]
print_pattern(pattern)
This results in the following output:
8 7 6
5 4 3
2 0 1
If you want to print the pattern in the opposite order you can pass a reversed list of your pattern, e.g.:
print_pattern(reversed(pattern))
Gives the following output:
1 0 2
3 4 5
6 7 8
This functions accepts an integer n and an iterable. It makes a list of tuples of width n from that iterable
def mat(n, it):
return list(zip(*[iter(it)]*n))

Extract subarray between certain value in Python

I have a list of values that are the result of merging many files. I need to pad some of the values. I know that each sub-section begins with the value -1. I am trying to basically extract a sub-array between -1's in the main array via iteration.
For example supposed this is the main list:
-1 1 2 3 4 5 7 -1 4 4 4 5 6 7 7 8 -1 0 2 3 5 -1
I would like to extract the values between the -1s:
list_a = 1 2 3 4 5 7
list_b = 4 4 4 5 6 7 7 8
list_c = 0 2 3 5 ...
list_n = a1 a2 a3 ... aM
I have extracted the indices for each -1 by searching through the main list:
minus_ones = [i for i, j in izip(count(), q) if j == -1]
I also assembled them as pairs using a common recipe:
def pairwise(iterable):
a, b = tee(iterable)
next(b, None)
return izip(a,b)
for index in pairwise(minus_ones):
print index
The next step I am trying to do is grab the values between the index pairs, for example:
list_b: (7 , 16) -> 4 4 4 5 6 7 7 8
so I can then do some work to those values (I will add a fixed int. to each value in each sub-array).
You mentioned numpy in the tags. If you're using it, have a look at np.split.
For example:
import numpy as np
x = np.array([-1, 1, 2, 3, 4, 5, 7, -1, 4, 4, 4, 5, 6, 7, 7, 8, -1, 0, 2,
3, 5, -1])
arrays = np.split(x, np.where(x == -1)[0])
arrays = [item[1:] for item in arrays if len(item) > 1]
This yields:
[array([1, 2, 3, 4, 5, 7]),
array([4, 4, 4, 5, 6, 7, 7, 8]),
array([0, 2, 3, 5])]
What's going on is that where will yield an array (actually a tuple of arrays, therefore the where(blah)[0]) of the indicies where the given expression is true. We can then pass these indicies to split to get a sequence of arrays.
However, the result will contain the -1's and an empty array at the start, if the sequence starts with -1. Therefore, we need to filter these out.
If you're not already using numpy, though, your (or #DSM's) itertools solution is probably a better choice.
If you only need the groups themselves and don't care about the indices of the groups (you could always reconstruct them, after all), I'd use itertools.groupby:
>>> from itertools import groupby
>>> seq = [-1, 1, 2, 3, 4, 5, 7, -1, 4, 4, 4, 5, 6, 7, 7, 8, -1, 0, 2, 3, 5, -1]
>>> groups = [list(g) for k,g in groupby(seq, lambda x: x != -1) if k]
>>> groups
[[1, 2, 3, 4, 5, 7], [4, 4, 4, 5, 6, 7, 7, 8], [0, 2, 3, 5]]
I missed the numpy tags, though: if you're working with numpy arrays, using np.split/np.where is a better choice.
I would do it something like this, which is a little different from the path you started down:
input_list = [-1,1,2,3,4,5,7,-1,4,4,4,5,6,7,7,8,-1,0,2,3,5,-1]
list_index = -1
new_lists = []
for i in input_list:
if i == -1:
list_index += 1
new_lists.append([])
continue
else:
print list_index
print new_lists
new_lists[list_index].append(i)
I think when you build your list, you can directly add the values to a string. So rather than starting with a list like xx = [], you can start with xx = '', and then do an update like xx = xx + ' ' + str (val). The result will be a string rather than a list. Then, you can just use the split() method on the strihg.
In [48]: xx
Out[48]: '-1 1 2 3 4 5 7 -1 4 4 4 5 6 7 7 8 -1 0 2 3 5 -1'
In [49]: xx.split('-1')
Out[49]: ['', ' 1 2 3 4 5 7 ', ' 4 4 4 5 6 7 7 8 ', ' 0 2 3 5 ', '']
In [50]: xx.split('-1')[1:-1]
Out[50]: [' 1 2 3 4 5 7 ', ' 4 4 4 5 6 7 7 8 ', ' 0 2 3 5 ']
Am sure you can take it from here ...

Categories

Resources