When I was trying to solve a scientific problem with Python (Numpy), a 'shape mismatch' error came up: "shape mismatch: objects cannot be broadcast to a single shape". I managed to reproduce the same error in a simpler form, as shown below:
import numpy as np
nx = 3; ny = 5
ff = np.ones([nx,ny,7])
def test(x, y):
z = 0.0
for i in range(7):
z = z + ff[x,y,i]
return z
print test(np.arange(nx),np.arange(ny))
When I tried to call test(x,y) with x=1,y=np.arange(ny), everything works fine. So what's going on here? Why can't the both parameters be numpy arrays?
UPDATE
I have worked out the problem with some hints from #Saullo Castro. Here's some updated info for you guys who tried to help but feel unclear about my intention:
Basically I created a mesh grid with dimension nx*ny and another array ff that stores some value for each node. In the above code, ff has 7 values for each node and I was trying to sum up the 7 values to get a new nx*ny array.
However, the "shape mismatch" error is not due to the summing process as many of you might have guess now. I have misunderstood the rule of functions taking ndarray objects as input parameters. I tried to pass np.arange(nx), np.arange(ny) to test() is not gonna give me what I desired, even if nx==ny.
Back to my original intention, I solve the problem by creating another function and used np.fromfunction to created the array:
def tt(x, y):
return np.fromfunction(lambda a,b: test(a,b), (x, y))
which is not perfect but it works. (In this example there seems to be no need to create a new function, but in my actual code I modified it a bit so it can be used for slice of the grid)
Anyway, I do believe there's a much better way compared to my kind of dirty solution. So if you have any idea about that, please share with us :).
Let's look into an array similar to your ff array:
nx = 3; ny = 4
ff = np.arange(nx*ny*5).reshape(nx,ny,5)
#array([[[ 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],
# [25, 26, 27, 28, 29],
# [30, 31, 32, 33, 34],
# [35, 36, 37, 38, 39]],
#
# [[40, 41, 42, 43, 44],
# [45, 46, 47, 48, 49],
# [50, 51, 52, 53, 54],
# [55, 56, 57, 58, 59]]])
When you index using arrays of indices a, b, c like in ff[a, b, c], a, b, c must have the same shape, and numpy will build a new array based on the indices. For example:
ff[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 2, 3], [0, 0, 0, 1, 1, 1]]
#array([ 0, 5, 20, 26, 51, 56])
This is called fancy indexing, which is like building an array with:
np.array([ff[0, 0, 0], ff[0, 1, 0], ff[1, 0, 0], ..., ff[2, 3, 1]])
In your case the f[x, y, i] will produce a shape mismatch error since a, b, c do not have the same shape.
Looks like you want to sum ff over the last dimension, with the 1st 2 dimensions covering their whole range. : is used to denote the whole range of a dimension:
def test():
z = 0.0
for i in range(7):
z = z + ff[:,:,i]
return z
print test()
But you can get the same result without looping, by using the sum method.
print ff.sum(axis=-1)
: is shorthand for 0:n
ff[0:nx, 0:ny, 0]==ff[:,:,0]
It is possible to index a block of ff with ranges, but you have to be much more careful about the shapes of the indexing arrays. For a beginner it is better to focus on getting slicing and broadcasting correct.
edit -
You can index an array like ff with arrays generated by meshgrid:
I,J = meshgrid(np.arange(nx),np.arange(ny),indexing='ij',sparse=False)
I.shape # (nx,ny)
ff[I,J,:]
also works with
I,J = meshgrid(np.arange(nx),np.arange(ny),indexing='ij',sparse=True)
I.shape # (nx,1)
J.shape # (1, ny)
ogrid and mgrid are alternatives to meshgrid.
Let's reproduce your problem in 2D case, so it is easier to see:
import numpy as np
a = np.arange(15).reshape(3,5)
x = np.arange(3)
y = np.arange(5)
Demo:
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
>>> a[x, y] # <- This is the error that you are getting
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
# You are getting the error because x and y are different lengths,
# If x and y were the same lengths, the code would work:
>>> a[x, x]
array([ 0, 6, 12])
# mixing arrays and scalars is not a problem
>>> a[x, 2]
array([ 2, 7, 12])
It is not clear in your question what you are trying to do or what result are you expecting. It seems, though, that you are trying to calculate a total with your variable z.
Check if the sum method produces the result that you need:
import numpy as np
nx = 3; ny = 5
ff = ff = np.array(np.arange(nx*ny*7)).reshape(nx,ny,7)
print ff.sum() # 5460
print ff.sum(axis=0) # array([[105, 108, 111, 114, 117, 120, 123],
# [126, 129, 132, 135, 138, 141, 144],
# [147, 150, 153, 156, 159, 162, 165],
# [168, 171, 174, 177, 180, 183, 186],
# [189, 192, 195, 198, 201, 204, 207]]) shape(5,7)
print ff.sum(axis=1) # array([[ 70, 75, 80, 85, 90, 95, 100],
# [245, 250, 255, 260, 265, 270, 275],
# [420, 425, 430, 435, 440, 445, 450]]) shape (3,7)
print ff.sum(axis=2) # array([[ 21, 70, 119, 168, 217],
# [266, 315, 364, 413, 462],
# [511, 560, 609, 658, 707]]) shape (3,5)
Related
I have four matrices, partially created from each other:
A is a 3D matrix that represents a stack of grayscale images and is of shape (n, h, w)
B is a 3D matrix that also represents a stack of images, where each slice is individually calculated from the corresponding slice in A and is also of shape (n, h, w)
C is a 2D matrix, containing the index with the maximum value of B in z direction and is of shape (h, w)
D is a 2D matrix, where a value from A is copied from a certain slice, which is indicated by the value in C at position (x, y).
A minimum example implemented with loops would look as follows:
import numpy as np
A = np.random.randint(0, 255, size=(3, 4, 5))
B = np.random.randint(0, 255, size=(3, 4, 5))
C = np.argmax(B, axis=0)
D = np.zeros(C.shape, dtype=int)
for y in range(C.shape[0]):
for x in range(C.shape[1]):
D[y, x] = A[C[y, x], y, x]
> A
array([[[ 24, 84, 155, 8, 147],
[ 25, 4, 49, 195, 57],
[ 93, 76, 233, 83, 177],
[ 70, 211, 201, 132, 239]],
[[177, 144, 247, 251, 207],
[242, 148, 28, 40, 105],
[181, 28, 132, 94, 196],
[166, 121, 72, 14, 14]],
[[ 55, 254, 140, 142, 14],
[112, 28, 85, 112, 145],
[ 16, 72, 16, 248, 179],
[160, 235, 225, 14, 211]]])
> B
array([[[246, 14, 55, 163, 161],
[ 3, 152, 128, 104, 203],
[ 43, 145, 59, 169, 242],
[106, 169, 31, 222, 240]],
[[ 41, 26, 239, 25, 65],
[ 47, 252, 205, 210, 138],
[194, 64, 135, 127, 101],
[ 63, 208, 179, 137, 59]],
[[112, 156, 183, 23, 253],
[ 35, 6, 233, 42, 100],
[ 66, 119, 102, 217, 64],
[ 82, 67, 135, 6, 8]]])
> C
array([[0, 2, 1, 0, 2],
[1, 1, 2, 1, 0],
[1, 0, 1, 2, 0],
[0, 1, 1, 0, 0]])
> D
array([[ 24, 254, 247, 8, 14],
[242, 148, 85, 40, 57],
[181, 76, 132, 248, 177],
[ 70, 121, 72, 132, 239]])
My question is: How to slice A with C efficiently eliminating the nested for-loops? My initial idea was to expand C to a 3D boolean mask, where only the positions [c, y, x] are set to True and then to simply multiply it elementwise with A and take the sum over z-axis. But I can't think of an pythonesque implementation without loops (and I probably wouldn't need to create a boolean mask anymore, if I'd knew how to write that).
The closest already implemented function I found is np.choose(), but it only takes 32 elements for C.
The standard approach here is to use np.take_along_axis() in conjunction with np.expand_dims() (the core idea is presented also in the np.argmax() documentation):
np.take_along_axis(A, np.expand_dims(C, axis=0), axis=0).squeeze()
Comparing the proposed approach with the explicit loops and the np.ogrid()-based approaches one would get:
import numpy as np
def take_by_axis_loop_fix(arr, pos):
result = np.zeros(pos.shape, dtype=int)
for i in range(pos.shape[0]):
for j in range(pos.shape[1]):
result[i, j] = arr[pos[i, j], i, j]
return result
def take_by_axis_ogrid_fix(arr, pos):
i, j = np.ogrid[:pos.shape[0], :pos.shape[1]]
return arr[pos[i, j], i, j]
def take_by_axis_np(arr, pos, axis=0):
return np.take_along_axis(arr, np.expand_dims(pos, axis=axis), axis=axis).squeeze()
def take_by_axis_ogrid(arr, pos, axis=0):
ij = tuple(np.ogrid[tuple(slice(None, d, None) for d in pos.shape)])
ij = ij[:axis] + (pos[ij],) + ij[axis:]
return arr[ij]
A_ = np.random.randint(0, 255, size=(300, 400, 500))
B_ = np.random.randint(0, 255, size=(300, 400, 500))
C_ = np.argmax(B_, axis=0)
funcs = take_by_axis_loop_fix, take_by_axis_ogrid_fix, take_by_axis_ogrid, take_by_axis_np
for func in funcs:
print(func.__name__, np.all(func(A_, C_) == take_by_axis_loop_fix(A_, C_)))
%timeit func(A_, C_)
print()
# take_by_axis_loop_fix True
# 10 loops, best of 3: 114 ms per loop
# take_by_axis_ogrid_fix True
# 100 loops, best of 3: 5.94 ms per loop
# take_by_axis_ogrid True
# 100 loops, best of 3: 5.54 ms per loop
# take_by_axis_np True
# 100 loops, best of 3: 3.34 ms per loop
indicating this to be the most efficient approach proposed so far.
Note also that the np.take_along_axis()-based and the take_by_axis_ogrid() approaches would work essentially unchanged for inputs with higher dimensionality, contrarily to the _fix approaches.
Particularly, take_by_axis_ogrid() is the axis-agnostic version of take_by_axis_ogrid_fix() which is, essentially, nth's answer.
y, x = np.ogrid[:C.shape[0],:C.shape[1]]
D = A[C[y, x], y, x]
Having two ndarrays, array d with shape (3,10,10) and array e with shape (3,10), how do I calculate the dot product of the first 10x10 matrix of d and the first row of e, the second 10x10 matrix of d and the second row of e, etc.
For example, having the following two arrays:
d = np.array([np.diag([1,1,1,1,1,1,1,1,1,1]),
np.diag([2,2,2,2,2,2,2,2,2,2]),
np.diag([3,3,3,3,3,3,3,3,3,3])])
e = np.arange(30).reshape((3,10))
How do I calculate the 3x10 array:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[20, 22, 24, 26, 28, 30, 32, 34, 36, 38],
[60, 63, 66, 69, 72, 75, 78, 81, 84, 87]])
I tried using np.dot and np.tensordot and also transposing and adding a new axis to e before doing so, but I coulnd't figure out how to solve this problem.
We can use np.einsum -
np.einsum('ijk,ij->ik',d,e)
Play around with its optimize flag to use BLAS.
Or np.matmul -
np.matmul(d,e[...,None])[...,0]
Note : On Python 3.x np.matmul could be replaced by # operator.
I have got a 1-d array where I have a pattern in the enteries. I will give an example. In the array arr, I have
first 4 enteries with single digits, next 4 enteries with two digits and then the next 6 enteries with 3 digits.
(This single, double, triple digit thing is just to highlight the pattern. The actual array have float numbers of similar values). The example 1-d array looks like:
import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])
Now, one complete pattern has total 4+4+6 = 14 enteries. This pattern (or repeating unit) is repeated several hundred thousand times so the length of my array is a multiple of 14 (14 * 2 = 28 in the example arr above).
Question:
I want to extract all the one digit enteries (first 4 numbers of one repeating unit), all the two digit enteries
(next 4 numbers of one repeating unit), and all the three digit enteries (next 6 numbers of one repeating unit).
This way I want to have my big arr splitted into three 1-d arrays. So the desired output is
arr1 = array([1, 2, 3, 4, 6, 5, 3, 2])
arr2 = array([11, 12, 13, 14, 21, 82, 53, 34])
arr3 = array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119])
My idea
One way could be to simply reshape it into 2d array since I know the number of repetitions (=28/14 = 2 in the example arr) and then use indexing to get all the first chunks of 4, 4 and 6
and then concatenate.
arr = arr.reshape(2, 14)
and then use slicing to get the chunks as
arr1 = np.concatenate(arr[:, 0:4])
arr2 = np.concatenate(arr[:, 4:8])
arr3 = np.concatenate(arr[:, 8:])
print (arr1, arr2, arr3)
# array([1, 2, 3, 4, 6, 5, 3, 2]),
# array([11, 12, 13, 14, 21, 82, 53, 34]),
# array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119]))
But I am interested in knowing an alternative and efficient solution using some sort of masking and slicing without converting first to a 2-d array.
You can also build the mask:
# if you know where your indices are, otherwise use a formula
mask = np.zeros((3, 2, 14), dtype=bool)
mask[0,:, 0:4] = True
mask[1,:, 4:8] = True
mask[2,:, 8:] = True
arr1, arr2, arr3 = (arr[m.flatten()] for m in mask)
print (arr1, arr2, arr3)
Using a mask of the pattern as requested (and supposing that arr length is an exact multiple of the mask length):
mask1 = [True]*4 + [False]*10
mask2 = [False]*4 + [True]*4 + [False]*6
mask3 = [False]*8 + [True]*6
Then you directly get the desired arrays by doing:
n_masks = (len(arr) // len(mask1))
arr1 = arr[mask1 * n_masks]
arr2 = arr[mask2 * n_masks]
arr3 = arr[mask3 * n_masks]
You could access the indices directly
import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])
run_length = 14
repetitions = 2
indices1 = [run_length * i + j for i in range(repetitions) for j in range(4)]
arr1 = arr[indices1]
indices2 = [run_length * i + j for i in range(repetitions) for j in range(4, 8)]
arr2 = arr[indices2]
indices3 = [run_length * i + j for i in range(repetitions) for j in range(8, 14)]
arr3 = arr[indices3]
print(arr1)
print(arr2)
print(arr3)
Output
[1 2 3 4 6 5 3 2]
[11 12 13 14 21 82 53 34]
[111 123 132 145 176 129 121 133 139 165 186 119]
You could put everything in a function like this:
import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])
def extract(arr, run_length, repetitions, pattern_lengths):
chunks = [0] + np.cumsum(pattern_lengths).tolist()
for start, end in zip(chunks, chunks[1:]):
indices = [run_length * i + j for i in range(repetitions) for j in range(start, end)]
yield arr[indices]
arr1, arr2, arr3 = list(extract(arr, 14, 2, [4, 4, 6]))
print(arr1)
print(arr2)
print(arr3)
We could simply reshape into 2D (remember reshaping creates a view and has zero memory overhead and hence virtually free on runtime) with the number of cols same as the pattern lenth (14 in the sample case). Then, slice out the first 4 entries for first array output, next 4 for second and 8th col onwards for the last one.
Since, we need flattened output, we can do so with .ravel().
Hence -
In [44]: a2d = arr.reshape(-1,14) # 2d view into arr
...: arr1,arr2,arr3 = a2d[:,:4].ravel(),a2d[:,4:8].ravel(),a2d[:,8:].ravel()
In [45]: arr1
Out[45]: array([1, 2, 3, 4, 6, 5, 3, 2])
In [46]: arr2
Out[46]: array([11, 12, 13, 14, 21, 82, 53, 34])
In [47]: arr3
Out[47]: array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119])
Now, say we are okay with 2D array outputs, then -
In [48]: arr1,arr2,arr3 = a2d[:,:4],a2d[:,4:8],a2d[:,8:]
In [49]: arr1
Out[49]:
array([[1, 2, 3, 4],
[6, 5, 3, 2]])
In [50]: arr2
Out[50]:
array([[11, 12, 13, 14],
[21, 82, 53, 34]])
In [51]: arr3
Out[51]:
array([[111, 123, 132, 145, 176, 129],
[121, 133, 139, 165, 186, 119]])
So, why take this? Because it's a view into the original input arr and hence as mentioned earlier has zero memory overhead and virtually free -
In [52]: np.shares_memory(arr,arr1)
Out[52]: True
and so on for other two arrays.
Is there a way to do multiple indexing in a numpy array as described below?
arr=np.array([55, 2, 3, 4, 5, 6, 7, 8, 9])
arr[np.arange(0,2):np.arange(5,7)]
output:
IndexError: too many indices for array
Desired output:
array([55,2,3,4,5],[2,3,4,5,6])
This problem might be similar to calculating a moving average over an array (but I want to do it without any function that is provided).
Here's an approach using strides -
start_index = np.arange(0,2)
L = 5 # Interval length
n = arr.strides[0]
strided = np.lib.stride_tricks.as_strided
out = strided(arr[start_index[0]:],shape=(len(start_index),L),strides=(n,n))
Sample run -
In [976]: arr
Out[976]: array([55, 52, 13, 64, 25, 76, 47, 18, 69, 88])
In [977]: start_index
Out[977]: array([2, 3, 4])
In [978]: L = 5
In [979]: out
Out[979]:
array([[13, 64, 25, 76, 47],
[64, 25, 76, 47, 18],
[25, 76, 47, 18, 69]])
I have a numpy array of numbers, for example,
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
I would like to find all the indexes of the elements within a specific range. For instance, if the range is (6, 10), the answer should be (3, 4, 5). Is there a built-in function to do this?
You can use np.where to get indices and np.logical_and to set two conditions:
import numpy as np
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
np.where(np.logical_and(a>=6, a<=10))
# returns (array([3, 4, 5]),)
As in #deinonychusaur's reply, but even more compact:
In [7]: np.where((a >= 6) & (a <=10))
Out[7]: (array([3, 4, 5]),)
Summary of the answers
For understanding what is the best answer we can do some timing using the different solution.
Unfortunately, the question was not well-posed so there are answers to different questions, here I try to point the answer to the same question. Given the array:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
The answer should be the indexes of the elements between a certain range, we assume inclusive, in this case, 6 and 10.
answer = (3, 4, 5)
Corresponding to the values 6,9,10.
To test the best answer we can use this code.
import timeit
setup = """
import numpy as np
import numexpr as ne
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
# or test it with an array of the similar size
# a = np.random.rand(100)*23 # change the number to the an estimate of your array size.
# we define the left and right limit
ll = 6
rl = 10
def sorted_slice(a,l,r):
start = np.searchsorted(a, l, 'left')
end = np.searchsorted(a, r, 'right')
return np.arange(start,end)
"""
functions = ['sorted_slice(a,ll,rl)', # works only for sorted values
'np.where(np.logical_and(a>=ll, a<=rl))[0]',
'np.where((a >= ll) & (a <=rl))[0]',
'np.where((a>=ll)*(a<=rl))[0]',
'np.where(np.vectorize(lambda x: ll <= x <= rl)(a))[0]',
'np.argwhere((a>=ll) & (a<=rl)).T[0]', # we traspose for getting a single row
'np.where(ne.evaluate("(ll <= a) & (a <= rl)"))[0]',]
functions2 = [
'a[np.logical_and(a>=ll, a<=rl)]',
'a[(a>=ll) & (a<=rl)]',
'a[(a>=ll)*(a<=rl)]',
'a[np.vectorize(lambda x: ll <= x <= rl)(a)]',
'a[ne.evaluate("(ll <= a) & (a <= rl)")]',
]
rdict = {}
for i in functions:
rdict[i] = timeit.timeit(i,setup=setup,number=1000)
print("%s -> %s s" %(i,rdict[i]))
print("Sorted:")
for w in sorted(rdict, key=rdict.get):
print(w, rdict[w])
Results
The results are reported in the following plot for a small array (on the top the fastest solution) as noted by #EZLearner they may vary depending on the size of the array. sorted slice could be faster for larger arrays, but it requires your array to be sorted, for arrays with over 10 M of entries ne.evaluate could be an option. Is hence always better to perform this test with an array of the same size as yours:
If instead of the indexes you want to extract the values you can perform the tests using functions2 but the results are almost the same.
I thought I would add this because the a in the example you gave is sorted:
import numpy as np
a = [1, 3, 5, 6, 9, 10, 14, 15, 56]
start = np.searchsorted(a, 6, 'left')
end = np.searchsorted(a, 10, 'right')
rng = np.arange(start, end)
rng
# array([3, 4, 5])
a = np.array([1,2,3,4,5,6,7,8,9])
b = a[(a>2) & (a<8)]
Other way is with:
np.vectorize(lambda x: 6 <= x <= 10)(a)
which returns:
array([False, False, False, True, True, True, False, False, False])
It is sometimes useful for masking time series, vectors, etc.
This code snippet returns all the numbers in a numpy array between two values:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] )
a[(a>6)*(a<10)]
It works as following:
(a>6) returns a numpy array with True (1) and False (0), so does (a<10). By multiplying these two together you get an array with either a True, if both statements are True (because 1x1 = 1) or False (because 0x0 = 0 and 1x0 = 0).
The part a[...] returns all values of array a where the array between brackets returns a True statement.
Of course you can make this more complicated by saying for instance
...*(1-a<10)
which is similar to an "and Not" statement.
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
np.argwhere((a>=6) & (a<=10))
Wanted to add numexpr into the mix:
import numpy as np
import numexpr as ne
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
np.where(ne.evaluate("(6 <= a) & (a <= 10)"))[0]
# array([3, 4, 5], dtype=int64)
Would only make sense for larger arrays with millions... or if you hitting a memory limits.
This may not be the prettiest, but works for any dimension
a = np.array([[-1,2], [1,5], [6,7], [5,2], [3,4], [0, 0], [-1,-1]])
ranges = (0,4), (0,4)
def conditionRange(X : np.ndarray, ranges : list) -> np.ndarray:
idx = set()
for column, r in enumerate(ranges):
tmp = np.where(np.logical_and(X[:, column] >= r[0], X[:, column] <= r[1]))[0]
if idx:
idx = idx & set(tmp)
else:
idx = set(tmp)
idx = np.array(list(idx))
return X[idx, :]
b = conditionRange(a, ranges)
print(b)
s=[52, 33, 70, 39, 57, 59, 7, 2, 46, 69, 11, 74, 58, 60, 63, 43, 75, 92, 65, 19, 1, 79, 22, 38, 26, 3, 66, 88, 9, 15, 28, 44, 67, 87, 21, 49, 85, 32, 89, 77, 47, 93, 35, 12, 73, 76, 50, 45, 5, 29, 97, 94, 95, 56, 48, 71, 54, 55, 51, 23, 84, 80, 62, 30, 13, 34]
dic={}
for i in range(0,len(s),10):
dic[i,i+10]=list(filter(lambda x:((x>=i)&(x<i+10)),s))
print(dic)
for keys,values in dic.items():
print(keys)
print(values)
Output:
(0, 10)
[7, 2, 1, 3, 9, 5]
(20, 30)
[22, 26, 28, 21, 29, 23]
(30, 40)
[33, 39, 38, 32, 35, 30, 34]
(10, 20)
[11, 19, 15, 12, 13]
(40, 50)
[46, 43, 44, 49, 47, 45, 48]
(60, 70)
[69, 60, 63, 65, 66, 67, 62]
(50, 60)
[52, 57, 59, 58, 50, 56, 54, 55, 51]
You can use np.clip() to achieve the same:
a = [1, 3, 5, 6, 9, 10, 14, 15, 56]
np.clip(a,6,10)
However, it holds the values less than and greater than 6 and 10 respectively.