Ordering a list - python

I have a list like this,
M=[[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19,
1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70,
92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16,
94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77,
73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27,
29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62,
98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
and I would like to sort it by the largest number on the "zero" position for each element in the list for example,
M=[[75], [95, 64], [82, 47, 17], [87, 35, 18, 10].....]
I tried to use a key but it didnt work well also I didnt know why it didnt work well..Here the key
def Len(elem):
for i in range(16):
y=len(K[i])
return elem[y-1]
y=sorted(K,key=Len)
print(y)
Maybe I just didnt understand the key function.
Thanks

Just use sorted (or list.sort) without a key. They already sort lexicographically.
>>> sorted(M, reverse=True)
[[99, 65, 4, 28, 6, 16, 70, 92], [95, 64], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [88, 2, 77, 73, 7, 63, 67], [75], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [41, 41, 26, 56, 83, 40, 80, 70, 33], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [18, 35, 87, 10], [17, 47, 82], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
edit:
Sorting the lists individually:
>>> [sorted(sublist, reverse=True) for sublist in M]
[[75], [95, 64], [82, 47, 17], [87, 35, 18, 10], [82, 65, 47, 20, 4], [75, 34, 23, 19, 3, 1], [88, 77, 73, 67, 63, 7, 2], [99, 92, 70, 65, 28, 16, 6, 4], [83, 80, 70, 56, 41, 41, 40, 33, 26], [94, 72, 48, 47, 41, 37, 33, 32, 29, 16], [97, 91, 71, 65, 53, 52, 51, 44, 43, 25, 14], [78, 77, 73, 70, 68, 57, 39, 33, 28, 17, 17, 11], [91, 91, 71, 58, 52, 50, 48, 43, 38, 29, 27, 17, 14], [89, 87, 73, 69, 68, 67, 66, 63, 53, 40, 31, 30, 16, 4], [98, 98, 93, 73, 70, 62, 60, 53, 38, 27, 23, 23, 9, 4, 4]]

Try operator itemgetter function as key.
Like this:
from operator import itemgetter
sorted(K,key=itemgetter(0))

try using index of each element :
for i in M:
M[M.index(i)]=sorted(i,reverse=True)

Related

List copy not working? [duplicate]

This question already has an answer here:
How to clone or copy a list?
17 answers
Copying nested lists in Python
2 answers
I got something with Python that I can't understand.
I have a list of lists, called data:
data = [[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
I want to create a copy of data, whose data would be reversed (1 becomes 99 and so on).
I then have the sorted_values and the reverse ones:
sorted_vals = [1, 2, 3, 4, 6, 7, 9, 10, 11, 14, 16, 17, 18, 19, 20, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 47, 48, 50, 51, 52, 53, 56, 57, 58, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 77, 78, 80, 82, 83, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99]
reverse_vals = [99, 98, 97, 95, 94, 93, 92, 91, 89, 88, 87, 83, 82, 80, 78, 77, 75, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 60, 58, 57, 56, 53, 52, 51, 50, 48, 47, 44, 43, 41, 40, 39, 38, 37, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 23, 20, 19, 18, 17, 16, 14, 11, 10, 9, 7, 6, 4, 3, 2, 1]
I create a copy of data:
rev_data = data[:]
Then, I change data while running through my list:
for index, item in enumerate(rev_data):
for s_index, s_item in enumerate(item):
rev_data[index][s_index] = reverse_val[sort_val.index(s_item)]
My problem is that whatever my method to create rev_data, data is also modified during the process!
I tried:
rev_data = list(data)
rev_data = data[:]
rev_data = []
rev_data.extend(data)
Each time, the final answer is correct, but data is also changed . . .
data = [[25], [4, 35], [83, 52, 18], [82, 64, 16, 91], [78, 95, 18, 52, 34], [80, 99, 77, 25, 97, 65], [14, 98, 23, 26, 93, 37, 32], [1, 34, 95, 71, 94, 87, 29, 9], [57, 57, 73, 43, 17, 58, 19, 29, 66], [57, 51, 27, 66, 52, 67, 63, 87, 6, 70], [44, 28, 53, 34, 75, 56, 10, 47, 3, 48, 88], [29, 89, 66, 71, 23, 26, 83, 20, 60, 31, 83, 41], [10, 28, 47, 62, 83, 88, 10, 56, 40, 50, 72, 70, 51], [37, 33, 95, 31, 11, 44, 32, 69, 26, 87, 30, 16, 58, 68], [95, 38, 2, 72, 77, 92, 29, 2, 26, 7, 62, 44, 39, 95, 77]]
data[:] creates a shallow copy of the list data. Since this is a list of lists, and you also want to copy the inner lists, you need a deep copy instead:
rev_data = copy.deepcopy(data)
or
rev_data = [x[:] for x in data]
use copy.deepcopy to copy nested mutable objects.
import copy
rev_data = copy.deepcopy(data)
..................... 
That is:
>>> import copy
>>> data = [[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
>>> reverse_vals = [99, 98, 97, 95, 94, 93, 92, 91, 89, 88, 87, 83, 82, 80, 78, 77, 75, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 60, 58, 57, 56, 53, 52, 51, 50, 48, 47, 44, 43, 41, 40, 39, 38, 37, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 23, 20, 19, 18, 17, 16, 14, 11, 10, 9, 7, 6, 4, 3, 2, 1]
>>> sorted_vals = [1, 2, 3, 4, 6, 7, 9, 10, 11, 14, 16, 17, 18, 19, 20, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 47, 48, 50, 51, 52, 53, 56, 57, 58, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 77, 78, 80, 82, 83, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99]
>>> for index, item in enumerate(rev_data):
... for s_index, s_item in enumerate(item):
... rev_data[index][s_index] = reverse_vals[sorted_vals.index(s_item)]
...
>>> data
[[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
>>> rev_data
[[25], [4, 35], [83, 52, 18], [82, 64, 16, 91], [78, 95, 18, 52, 34], [80, 99, 77, 25, 97, 65], [14, 98, 23, 26, 93, 37, 32], [1, 34, 95, 71, 94, 87, 29, 9], [57, 57, 73, 43, 17, 58, 19, 29, 66], [57, 51, 27, 66, 52, 67, 63, 87, 6, 70], [44, 28, 53, 34, 75, 56, 10, 47, 3, 48, 88], [29, 89, 66, 71, 23, 26, 83, 20, 60, 31, 83, 41], [10, 28, 47, 62, 83, 88, 10, 56, 40, 50, 72, 70, 51], [37, 33, 95, 31, 11, 44, 32, 69, 26, 87, 30, 16, 58, 68], [95, 38, 2, 72, 77, 92, 29, 2, 26, 7, 62, 44, 39, 95, 77]]
You have a list of nested lists, so you need to copy two levels deep.
data_copy = [inner_list[:] for inner_list in data]
reverse_data = reversed(data)
reverse_data will be an iterator. You can either traverse it, or force it to a list with list(reverse_data).
More on built-in functions: http://docs.python.org/library/functions.html#reversed
- Keep it under your pillow.
Edit: if you just want to have a list of values subtracted from 100:
from operator import sub
from functools import partial
subtract_map = partial(map, partial(sub,100)) # this is more convenient than a nested list comprehension
complements = [subtract_map(l) for l in data]

Copy or Clone a list of list [duplicate]

This question already has an answer here:
How to clone or copy a list?
17 answers
Copying nested lists in Python
2 answers
I got something with Python that I can't understand.
I have a list of lists, called data:
data = [[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
I want to create a copy of data, whose data would be reversed (1 becomes 99 and so on).
I then have the sorted_values and the reverse ones:
sorted_vals = [1, 2, 3, 4, 6, 7, 9, 10, 11, 14, 16, 17, 18, 19, 20, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 47, 48, 50, 51, 52, 53, 56, 57, 58, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 77, 78, 80, 82, 83, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99]
reverse_vals = [99, 98, 97, 95, 94, 93, 92, 91, 89, 88, 87, 83, 82, 80, 78, 77, 75, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 60, 58, 57, 56, 53, 52, 51, 50, 48, 47, 44, 43, 41, 40, 39, 38, 37, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 23, 20, 19, 18, 17, 16, 14, 11, 10, 9, 7, 6, 4, 3, 2, 1]
I create a copy of data:
rev_data = data[:]
Then, I change data while running through my list:
for index, item in enumerate(rev_data):
for s_index, s_item in enumerate(item):
rev_data[index][s_index] = reverse_val[sort_val.index(s_item)]
My problem is that whatever my method to create rev_data, data is also modified during the process!
I tried:
rev_data = list(data)
rev_data = data[:]
rev_data = []
rev_data.extend(data)
Each time, the final answer is correct, but data is also changed . . .
data = [[25], [4, 35], [83, 52, 18], [82, 64, 16, 91], [78, 95, 18, 52, 34], [80, 99, 77, 25, 97, 65], [14, 98, 23, 26, 93, 37, 32], [1, 34, 95, 71, 94, 87, 29, 9], [57, 57, 73, 43, 17, 58, 19, 29, 66], [57, 51, 27, 66, 52, 67, 63, 87, 6, 70], [44, 28, 53, 34, 75, 56, 10, 47, 3, 48, 88], [29, 89, 66, 71, 23, 26, 83, 20, 60, 31, 83, 41], [10, 28, 47, 62, 83, 88, 10, 56, 40, 50, 72, 70, 51], [37, 33, 95, 31, 11, 44, 32, 69, 26, 87, 30, 16, 58, 68], [95, 38, 2, 72, 77, 92, 29, 2, 26, 7, 62, 44, 39, 95, 77]]
data[:] creates a shallow copy of the list data. Since this is a list of lists, and you also want to copy the inner lists, you need a deep copy instead:
rev_data = copy.deepcopy(data)
or
rev_data = [x[:] for x in data]
use copy.deepcopy to copy nested mutable objects.
import copy
rev_data = copy.deepcopy(data)
..................... 
That is:
>>> import copy
>>> data = [[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
>>> reverse_vals = [99, 98, 97, 95, 94, 93, 92, 91, 89, 88, 87, 83, 82, 80, 78, 77, 75, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 60, 58, 57, 56, 53, 52, 51, 50, 48, 47, 44, 43, 41, 40, 39, 38, 37, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 23, 20, 19, 18, 17, 16, 14, 11, 10, 9, 7, 6, 4, 3, 2, 1]
>>> sorted_vals = [1, 2, 3, 4, 6, 7, 9, 10, 11, 14, 16, 17, 18, 19, 20, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 47, 48, 50, 51, 52, 53, 56, 57, 58, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 77, 78, 80, 82, 83, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99]
>>> for index, item in enumerate(rev_data):
... for s_index, s_item in enumerate(item):
... rev_data[index][s_index] = reverse_vals[sorted_vals.index(s_item)]
...
>>> data
[[75], [95, 64], [17, 47, 82], [18, 35, 87, 10], [20, 4, 82, 47, 65], [19, 1, 23, 75, 3, 34], [88, 2, 77, 73, 7, 63, 67], [99, 65, 4, 28, 6, 16, 70, 92], [41, 41, 26, 56, 83, 40, 80, 70, 33], [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], [4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23]]
>>> rev_data
[[25], [4, 35], [83, 52, 18], [82, 64, 16, 91], [78, 95, 18, 52, 34], [80, 99, 77, 25, 97, 65], [14, 98, 23, 26, 93, 37, 32], [1, 34, 95, 71, 94, 87, 29, 9], [57, 57, 73, 43, 17, 58, 19, 29, 66], [57, 51, 27, 66, 52, 67, 63, 87, 6, 70], [44, 28, 53, 34, 75, 56, 10, 47, 3, 48, 88], [29, 89, 66, 71, 23, 26, 83, 20, 60, 31, 83, 41], [10, 28, 47, 62, 83, 88, 10, 56, 40, 50, 72, 70, 51], [37, 33, 95, 31, 11, 44, 32, 69, 26, 87, 30, 16, 58, 68], [95, 38, 2, 72, 77, 92, 29, 2, 26, 7, 62, 44, 39, 95, 77]]
You have a list of nested lists, so you need to copy two levels deep.
data_copy = [inner_list[:] for inner_list in data]
reverse_data = reversed(data)
reverse_data will be an iterator. You can either traverse it, or force it to a list with list(reverse_data).
More on built-in functions: http://docs.python.org/library/functions.html#reversed
- Keep it under your pillow.
Edit: if you just want to have a list of values subtracted from 100:
from operator import sub
from functools import partial
subtract_map = partial(map, partial(sub,100)) # this is more convenient than a nested list comprehension
complements = [subtract_map(l) for l in data]

Selecting every n indices of an array

If I have an array that is 100 elements in length, what is the most Pythonic way to get every n indices. For example, if I wanted every 5 indices of an array a, how could I get an array b=[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14],...], where each element of b is a sub-array of every 5 indices?
You simply want to reshape your array:
>>> arr = np.arange(100)
>>> arr
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, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])
>>> arr.reshape(-1, 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],
[60, 61, 62, 63, 64],
[65, 66, 67, 68, 69],
[70, 71, 72, 73, 74],
[75, 76, 77, 78, 79],
[80, 81, 82, 83, 84],
[85, 86, 87, 88, 89],
[90, 91, 92, 93, 94],
[95, 96, 97, 98, 99]])
Note, I used -1 on the first axis, numpy is smart enough to "solve the equation" as long as you give it every other axis explicitly. You could have, of course, done this completely explicitly:
>>> arr.reshape(20, 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],
[60, 61, 62, 63, 64],
[65, 66, 67, 68, 69],
[70, 71, 72, 73, 74],
[75, 76, 77, 78, 79],
[80, 81, 82, 83, 84],
[85, 86, 87, 88, 89],
[90, 91, 92, 93, 94],
[95, 96, 97, 98, 99]])
Update:
If you are using lists, a very pythonic way to do it:
size = 5 # the number of elements of each sublists
l = list(range(100))
result = [l[step:step + size] for step in range(0, len(l), size)]
Ouput:
[[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],
[60, 61, 62, 63, 64], [65, 66, 67, 68, 69],
[70, 71, 72, 73, 74], [75, 76, 77, 78, 79],
[80, 81, 82, 83, 84], [85, 86, 87, 88, 89],
[90, 91, 92, 93, 94], [95, 96, 97, 98, 99]]
>>> L = range(100)
>>> step = 5
>>> [L[i:i+step] for i in range(0, len(L), step)]
[[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],
[60, 61, 62, 63, 64],
[65, 66, 67, 68, 69],
[70, 71, 72, 73, 74],
[75, 76, 77, 78, 79],
[80, 81, 82, 83, 84],
[85, 86, 87, 88, 89],
[90, 91, 92, 93, 94],
[95, 96, 97, 98, 99]]
Seems a natural way to do it to me.

Moving window with complete boundary in Python

I have been using rolling/moving windows lately and all implementations I have seen so far ignore values contained in the boundaries of the array if these values can not be placed in a complete window. For example, assume you have this array:
import numpy as np
np.arange(10*10).reshape(10,10)
Out[1]:
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],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
Using view_as_windows from scikit-image, you can see there are several elements (last two columns and last two rows) that can't be placed inside another 4x4 window:
from skimage.util import view_as_windows
view_as_windows(np.arange(10*10).reshape(10,10), (4,4),4)
Out[14]:
array([[[[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33]],
[[ 4, 5, 6, 7],
[14, 15, 16, 17],
[24, 25, 26, 27],
[34, 35, 36, 37]]],
[[[40, 41, 42, 43],
[50, 51, 52, 53],
[60, 61, 62, 63],
[70, 71, 72, 73]],
[[44, 45, 46, 47],
[54, 55, 56, 57],
[64, 65, 66, 67],
[74, 75, 76, 77]]]])
I think sklearn.feature_extraction.image.extract_patches_2d behaves in the same way. As far as I understand, both use stride tricks to obtain memory views of the array. However, I'd like to be able to obtain partial windows even if they don't have the same size.

Building block matrix from array in the correct order

I have a numpy array similar to this:
a = np.arange(0,100).reshape(25,4)
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],
[60, 61, 62, 63],
[64, 65, 66, 67],
[68, 69, 70, 71],
[72, 73, 74, 75],
[76, 77, 78, 79],
[80, 81, 82, 83],
[84, 85, 86, 87],
[88, 89, 90, 91],
[92, 93, 94, 95],
[96, 97, 98, 99]])
I want to use this array to create a block matrix in a very precise order. Each block must be a square matrix that is constructed from the corresponding column of a. Therefore, in this case, we have 4 5X5 blocks. One way to do this is the following:
a = np.arange(0,100).reshape(25,4)
A = a[:, 0].reshape(np.sqrt(a.shape[0]), np.sqrt(a.shape[0]))
B = a[:, 1].reshape(np.sqrt(a.shape[0]), np.sqrt(a.shape[0]))
C = a[:, 2].reshape(np.sqrt(a.shape[0]), np.sqrt(a.shape[0]))
D = a[:, 3].reshape(np.sqrt(a.shape[0]), np.sqrt(a.shape[0]))
np.bmat([[A,B],[C,D]])
matrix([[ 0, 4, 8, 12, 16,| 1, 5, 9, 13, 17],
[20, 24, 28, 32, 36,| 21, 25, 29, 33, 37],
[40, 44, 48, 52, 56,| 41, 45, 49, 53, 57],
[60, 64, 68, 72, 76,| 61, 65, 69, 73, 77],
[80, 84, 88, 92, 96,| 81, 85, 89, 93, 97],
--------------------------------------- ,
[ 2, 6, 10, 14, 18,| 3, 7, 11, 15, 19],
[22, 26, 30, 34, 38,| 23, 27, 31, 35, 39],
[42, 46, 50, 54, 58,| 43, 47, 51, 55, 59],
[62, 66, 70, 74, 78,| 63, 67, 71, 75, 79],
[82, 86, 90, 94, 98,| 83, 87, 91, 95, 99]])
However, I need to build this matrix without creating each matrix "manually" and be able to generalize this approach to more dimensions (3X3, 4X4, etc)
Thanks!
As a (long) single liner:
In [14]: a = np.arange(0,100).reshape(25,4)
In [15]: a.T.reshape(2, 2, 5, 5).transpose(0, 2, 1, 3).reshape(10, 10)
Out[15]:
array([[ 0, 4, 8, 12, 16, 1, 5, 9, 13, 17],
[20, 24, 28, 32, 36, 21, 25, 29, 33, 37],
[40, 44, 48, 52, 56, 41, 45, 49, 53, 57],
[60, 64, 68, 72, 76, 61, 65, 69, 73, 77],
[80, 84, 88, 92, 96, 81, 85, 89, 93, 97],
[ 2, 6, 10, 14, 18, 3, 7, 11, 15, 19],
[22, 26, 30, 34, 38, 23, 27, 31, 35, 39],
[42, 46, 50, 54, 58, 43, 47, 51, 55, 59],
[62, 66, 70, 74, 78, 63, 67, 71, 75, 79],
[82, 86, 90, 94, 98, 83, 87, 91, 95, 99]])
In case it is relevant, note that the last reshape triggers a copy, so what you get is a new array, not a view into the old one.
And for the general case, if you have mxn blocks of shape pxq you could do:
In [24]: m = 4; n = 2; p = 3; q = 5
In [25]: a = np.arange(m*n*p*q).reshape(p*q, m*n)
In [26]: a.T.reshape(m, n, p, q).transpose(0, 2, 1, 3).reshape(m*p, n*q)
Out[26]:
array([[ 0, 8, 16, 24, 32, 1, 9, 17, 25, 33],
[ 40, 48, 56, 64, 72, 41, 49, 57, 65, 73],
[ 80, 88, 96, 104, 112, 81, 89, 97, 105, 113],
[ 2, 10, 18, 26, 34, 3, 11, 19, 27, 35],
[ 42, 50, 58, 66, 74, 43, 51, 59, 67, 75],
[ 82, 90, 98, 106, 114, 83, 91, 99, 107, 115],
[ 4, 12, 20, 28, 36, 5, 13, 21, 29, 37],
[ 44, 52, 60, 68, 76, 45, 53, 61, 69, 77],
[ 84, 92, 100, 108, 116, 85, 93, 101, 109, 117],
[ 6, 14, 22, 30, 38, 7, 15, 23, 31, 39],
[ 46, 54, 62, 70, 78, 47, 55, 63, 71, 79],
[ 86, 94, 102, 110, 118, 87, 95, 103, 111, 119]])

Resources