Related
Code:
lst = []
for _ in range(int(input())):
T = int(input())
for i in range(T):
matrix = list(map(int, input().split()))
lst.append(matrix)
print(lst)
Input:
3
4
1 2 3 4
2 1 4 3
3 4 1 2
4 3 2 1
4
2 2 2 2
2 3 2 3
2 2 2 3
2 2 2 2
3
2 1 3
1 3 2
1 2 3
On inputting this matrix, the expected output should be
[[1, 2, 3, 4], [2, 1, 4, 3], [3, 4, 1, 2], [4, 3, 2, 1]] and so on for other but the matrix is adding with other matrix at last.
I want to retrieve [[2, 1, 3], [1, 3, 2], [1, 2, 3]]. Getting [[1, 2, 3, 4], [2, 1, 4, 3], [3, 4, 1, 2], [4, 3, 2, 1], [2, 2, 2, 2], [2, 3, 2, 3], [2, 2, 2, 3], [2, 2, 2, 2], [2, 1, 3], [1, 3, 2], [1, 2, 3]].
How can I do so??
You're close. Instead of appending the rows of each matrix to your list, append the rows to a new matrix and then append the matrices to a list. Something like
lst = []
for _ in range(int(input())): # Loop over number of matrices
T = int(input())
matrix = []
for i in range(T): # Loop over each row
row = list(map(int, input().split()))
matrix.append(row)
lst.append(matrix)
Now lst[-1] will give you the last 2D matrix in the sequence.
This question already has answers here:
Quick way to upsample numpy array by nearest neighbor tiling [duplicate]
(3 answers)
Closed 3 years ago.
I have a 2d array, lets say the array is:
1 2 3
4 5 6
I want it to repeat 3 times on both axis, so it will look like:
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
Ive tried using numpy.repeat but unsuccessful.
any suggestions? thx
You can do it with the kronicker product, np.kron and a ones array of the size of the block.
a = np.arange(6).reshape(2,3) + 1
np.kron(a, np.ones((3,3), dtype = a.dtype))
Out[]:
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6]])
You can do it with numpy repeat
>>> data = np.array([[1,2,3],[4,5,6]])
>>> data
array([[1, 2, 3],
[4, 5, 6]])
>>> np.repeat(data,[3,3,3],axis=1).repeat([3,3],axis=0)
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6]])
I want duplicate rows in numpy arrays based on the numeric value of the first entry in each row. So if the value is 1, then the row isn't duplicated, but if the value is 3 that row will be represented 3 times. I tried to use np.repeat and np.tile but I don't know if they're the right tool for this and I haven't figured out if there is a way to do it yet.
Here are my randomly generated arrays :
[[[3 1 3 1 2]
[4 4 4 2 0]
[3 4 4 4 0]
[1 4 3 3 0]]
[[4 2 0 2 1]
[2 1 2 0 3]
[4 1 3 4 3]
[2 3 2 0 0]]]
My goal is to end up with this:
[[[3 1 3 1 2]
[3 1 3 1 2]
[3 1 3 1 2]
[4 4 4 2 0]
[4 4 4 2 0]
[4 4 4 2 0]
[4 4 4 2 0]
[3 4 4 4 0]
[3 4 4 4 0]
[3 4 4 4 0]
[1 4 3 3 0]]
[[4 2 0 2 1]
[4 2 0 2 1]
[4 2 0 2 1]
[4 2 0 2 1]
[2 1 2 0 3]
[2 1 2 0 3]
[4 1 3 4 3]
[4 1 3 4 3]
[4 1 3 4 3]
[4 1 3 4 3]
[2 3 2 0 0]
[2 3 2 0 0]]]
Here is the code I have so far
array = np.random.randint(5, size = (2, 4,5))
for a in array:
for b in a:
array = np.tile(a, (b[0],1))
If I print b[0], I can get each value. I want to use those values to duplicate each row.
3
4
3
1
4
2
4
2
So I thought I could loop through those values and multiply each row by its corresponding value to add new rows, but my result only duplicates the second array one time.
[[4 2 0 2 1]
[2 1 2 0 3]
[4 1 3 4 3]
[2 3 2 0 0]
[4 2 0 2 1]
[2 1 2 0 3]
[4 1 3 4 3]
[2 3 2 0 0]]
Where am I going wrong? Should I not use np.tile?
Since there is no guarantee that your original 2D sub-arrays in the 3D source array will have the same shape after performing this operation, they cannot in general be stacked back into a 3D array.
You can get a list of arrays with np.repeat by passing the first column of each 2D array as the number of repeats. It will then repeat each row the corresponding number of times:
from pprint import pprint
result = ([np.repeat(a[i], a[i, :, 0], axis=0) for i in range(a.shape[0])])
pprint(result)
Output:
[array([[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[1, 4, 3, 3, 0]]),
array([[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[2, 1, 2, 0, 3],
[2, 1, 2, 0, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[2, 3, 2, 0, 0],
[2, 3, 2, 0, 0]])]
Use numpy.repeat with np.arange:
import numpy as np
arr = np.array([[[3, 1, 3, 1, 2],
[4, 4, 4, 2, 0],
[3, 4, 4, 4, 0],
[1, 4, 3, 3, 0]],
[[4, 2, 0, 2, 1],
[2, 1, 2, 0, 3],
[4, 1, 3, 4, 3],
[2, 3, 2, 0, 0]]])
arr2d = np.vstack(arr)
dup = arr2d[np.repeat(np.arange(arr2d.shape[0]), arr2d[:,0])]
np.split(dup, np.cumsum(np.sum(np.split(arr2d[:,0], arr.shape[0]), 1)))[:-1]
Output:
[array([[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[1, 4, 3, 3, 0]]),
array([[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[2, 1, 2, 0, 3],
[2, 1, 2, 0, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[2, 3, 2, 0, 0],
[2, 3, 2, 0, 0]])]
Since the 2d-arrays do not always have same shape, most of the time it will yield list of arrays. Such inconsistency is not so well handled by numpy.
In such case, you can simply use itertools.repeat with list comprehension. (Though it looks quite similar to #gmds' answer)
Given l:
import itertools
l = [[[3, 1, 3, 1, 2], [4, 4, 4, 2, 0], [3, 4, 4, 4, 0], [1, 4, 3, 3, 0]],
[[4, 2, 0, 2, 1], [2, 1, 2, 0, 3], [4, 1, 3, 4, 3], [2, 3, 2, 0, 0]]]
[[j for i in sub for j in itertools.repeat(i, i[0])] for sub in l]
Output:
[[[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[3, 1, 3, 1, 2],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[4, 4, 4, 2, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[3, 4, 4, 4, 0],
[1, 4, 3, 3, 0]],
[[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[4, 2, 0, 2, 1],
[2, 1, 2, 0, 3],
[2, 1, 2, 0, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[4, 1, 3, 4, 3],
[2, 3, 2, 0, 0],
[2, 3, 2, 0, 0]]]
I have three lists:
a = [0,1,2]
b = [3,4,5]
c = [aab, abb, aaa]
How to create all three-element combinations? Where sequences from the list c tell you which list can be used to choose numbers for a given place in a given output sequence
For example (pseudocode):
for i=0 in range(len(c)):
print: [0,1,3]
[0,1,4]
...
[0,2,5]
...
[1,2,4]
[1,2,5]
And the same for the rest of the i indexes. Where the values in individual sublistas can not be repeated.
I will be very grateful for any tips.
This generator function will handle 'ab' template strings with the a's and b's in any order, and the output lists will not contain repeated items if the a and b lists are disjoint. We use itertools.combinations to generate combinations of the required order, and combine the a and b combinations using itertools.product. We get them in the correct order by turning each a and b combination into an iterator and select from the correct iterator via a dictionary.
from itertools import combinations, product
def groups(a, b, c):
for pat in c:
acombo = combinations(a, pat.count('a'))
bcombo = combinations(b, pat.count('b'))
for ta, tb in product(acombo, bcombo):
d = {'a': iter(ta), 'b': iter(tb)}
yield [next(d[k]) for k in pat]
# tests
a = [0,1,2]
b = [3,4,5]
templates = ['aab', 'abb', 'aaa'], ['aba'], ['bab']
for c in templates:
print('c', c)
for i, t in enumerate(groups(a, b, c), 1):
print(i, t)
print()
output
c ['aab', 'abb', 'aaa']
1 [0, 1, 3]
2 [0, 1, 4]
3 [0, 1, 5]
4 [0, 2, 3]
5 [0, 2, 4]
6 [0, 2, 5]
7 [1, 2, 3]
8 [1, 2, 4]
9 [1, 2, 5]
10 [0, 3, 4]
11 [0, 3, 5]
12 [0, 4, 5]
13 [1, 3, 4]
14 [1, 3, 5]
15 [1, 4, 5]
16 [2, 3, 4]
17 [2, 3, 5]
18 [2, 4, 5]
19 [0, 1, 2]
c ['aba']
1 [0, 3, 1]
2 [0, 4, 1]
3 [0, 5, 1]
4 [0, 3, 2]
5 [0, 4, 2]
6 [0, 5, 2]
7 [1, 3, 2]
8 [1, 4, 2]
9 [1, 5, 2]
c ['bab']
1 [3, 0, 4]
2 [3, 0, 5]
3 [4, 0, 5]
4 [3, 1, 4]
5 [3, 1, 5]
6 [4, 1, 5]
7 [3, 2, 4]
8 [3, 2, 5]
9 [4, 2, 5]
I should mention that even though combinations returns iterators, and product happily takes iterators as arguments, it has to make lists from the iterators because it has to run over the iterator contents multiple times. So if the number of combinations is huge this can consume a fair amount of RAM.
If you want permutations instead of combinations, that's easy. We just call itertools.permutations instead of itertools.combinations.
from itertools import permutations, product
def groups(a, b, c):
for pat in c:
acombo = permutations(a, pat.count('a'))
bcombo = permutations(b, pat.count('b'))
for ta, tb in product(acombo, bcombo):
d = {'a': iter(ta), 'b': iter(tb)}
yield [next(d[k]) for k in pat]
# tests
a = [0,1,2]
b = [3,4,5]
templates = ['aaa'], ['abb']
for c in templates:
print('c', c)
for i, t in enumerate(groups(a, b, c), 1):
print(i, t)
print()
output
c ['aaa']
1 [0, 1, 2]
2 [0, 2, 1]
3 [1, 0, 2]
4 [1, 2, 0]
5 [2, 0, 1]
6 [2, 1, 0]
c ['abb']
1 [0, 3, 4]
2 [0, 3, 5]
3 [0, 4, 3]
4 [0, 4, 5]
5 [0, 5, 3]
6 [0, 5, 4]
7 [1, 3, 4]
8 [1, 3, 5]
9 [1, 4, 3]
10 [1, 4, 5]
11 [1, 5, 3]
12 [1, 5, 4]
13 [2, 3, 4]
14 [2, 3, 5]
15 [2, 4, 3]
16 [2, 4, 5]
17 [2, 5, 3]
18 [2, 5, 4]
Finally, here's a version that handles any number of lists, and template strings of any length. It only accepts a single template string per call, but that shouldn't be an issue. You can also choose whether you want to generate permutations or combinations via an optional keyword arg.
from itertools import permutations, combinations, product
def groups(sources, template, mode='P'):
func = permutations if mode == 'P' else combinations
keys = sources.keys()
combos = [func(sources[k], template.count(k)) for k in keys]
for t in product(*combos):
d = {k: iter(v) for k, v in zip(keys, t)}
yield [next(d[k]) for k in template]
# tests
sources = {
'a': [0, 1, 2],
'b': [3, 4, 5],
'c': [6, 7, 8],
}
templates = 'aa', 'abc', 'abba', 'cab'
for template in templates:
print('\ntemplate', template)
for i, t in enumerate(groups(sources, template, mode='C'), 1):
print(i, t)
output
template aa
1 [0, 1]
2 [0, 2]
3 [1, 2]
template abc
1 [0, 3, 6]
2 [0, 3, 7]
3 [0, 3, 8]
4 [0, 4, 6]
5 [0, 4, 7]
6 [0, 4, 8]
7 [0, 5, 6]
8 [0, 5, 7]
9 [0, 5, 8]
10 [1, 3, 6]
11 [1, 3, 7]
12 [1, 3, 8]
13 [1, 4, 6]
14 [1, 4, 7]
15 [1, 4, 8]
16 [1, 5, 6]
17 [1, 5, 7]
18 [1, 5, 8]
19 [2, 3, 6]
20 [2, 3, 7]
21 [2, 3, 8]
22 [2, 4, 6]
23 [2, 4, 7]
24 [2, 4, 8]
25 [2, 5, 6]
26 [2, 5, 7]
27 [2, 5, 8]
template abba
1 [0, 3, 4, 1]
2 [0, 3, 5, 1]
3 [0, 4, 5, 1]
4 [0, 3, 4, 2]
5 [0, 3, 5, 2]
6 [0, 4, 5, 2]
7 [1, 3, 4, 2]
8 [1, 3, 5, 2]
9 [1, 4, 5, 2]
template cab
1 [6, 0, 3]
2 [7, 0, 3]
3 [8, 0, 3]
4 [6, 0, 4]
5 [7, 0, 4]
6 [8, 0, 4]
7 [6, 0, 5]
8 [7, 0, 5]
9 [8, 0, 5]
10 [6, 1, 3]
11 [7, 1, 3]
12 [8, 1, 3]
13 [6, 1, 4]
14 [7, 1, 4]
15 [8, 1, 4]
16 [6, 1, 5]
17 [7, 1, 5]
18 [8, 1, 5]
19 [6, 2, 3]
20 [7, 2, 3]
21 [8, 2, 3]
22 [6, 2, 4]
23 [7, 2, 4]
24 [8, 2, 4]
25 [6, 2, 5]
26 [7, 2, 5]
27 [8, 2, 5]
from itertools import product, chain
setups = ['aab', 'abb', 'aaa']
sources = {
'a': [0,1,2],
'b': [3,4,5]
}
combinations = (product(*map(sources.get, setup)) for setup in setups)
combinations is a nested lazy iterator (i.e. nothing is stored in memory and calculated, yet). If you want to get an iterator of lists
combinations = map(list, (product(*map(sources.get, setup)) for setup in setups))
Or you might want to flatten the result:
combinations = chain.from_iterable(product(*map(sources.get, setup)) for setup in setups)
If I understand it correctly, you can achieve the goal with a dictionary bookkeeping the correspondence of a character like "a" to a variable name a.
from collections import defaultdict
a = [0,1,2]
b = [3,4,5]
c = ["aab", "abb", "aaa"]
d = {"a": a, "b": b}
d2 = defaultdict(list)
for seq in c:
l = []
for idx, v in enumerate(seq):
l.append(d[v][idx])
print(l)
d2[seq].append(l)
# Out:
#[0, 1, 5]
#[0, 4, 5]
#[0, 1, 2]
print(d2)
# defaultdict(<class 'list'>, {'aab': [[0, 1, 5]], 'abb': [[0, 4, 5]], 'aaa': [[0, 1, 2]]})
Put the lists in a dictionary so you can access them with strings.
Use the characters in each sequence to determine which lists to use.
Use itertools.product to get the combinations.
import itertools, collections
from pprint import pprint
d = {'a':[0,1,2], 'b':[3,4,5]}
c = ['aab', 'abb', 'aaa']
def f(t):
t = collections.Counter(t)
return max(t.values()) < 2
for seq in c:
data = (d[char] for char in seq)
print(f'sequence: {seq}')
pprint(list(filter(f, itertools.product(*data))))
print('***************************')
Result for sequence 'abb':
sequence: abb
[(0, 3, 4),
(0, 3, 5),
(0, 4, 3),
(0, 4, 5),
(0, 5, 3),
(0, 5, 4),
(1, 3, 4),
(1, 3, 5),
(1, 4, 3),
(1, 4, 5),
(1, 5, 3),
(1, 5, 4),
(2, 3, 4),
(2, 3, 5),
(2, 4, 3),
(2, 4, 5),
(2, 5, 3),
(2, 5, 4)]
edit to filter out tuples with duplicates
I like the idea of a callable dict that can be used with map. It could be used here.
class CallDict(dict):
def __call__(self, key):
return self[key] #self.get(key)
e = CallDict([('a',[0,1,2]), ('b',[3,4,5])])
for seq in c:
data = map(e, seq)
print(f'sequence: {seq}')
for thing in filter(f, itertools.product(*data)):
print(thing)
print('***************************')
I couldn't help myself, here is a generic version of #PM2Ring's solution/answer. Instead of filtering out unwanted items, it doesn't produce them in the first place.
d = {'a':[0,1,2], 'b':[3,4,5]}
c = ['aab', 'abb', 'aaa', 'aba']
def g(d, c):
for seq in c:
print(f'sequence: {seq}')
counts = collections.Counter(seq)
## data = (itertools.combinations(d[key],r) for key, r in counts.items())
data = (itertools.permutations(d[key],r) for key, r in counts.items())
for thing in itertools.product(*data):
q = {key:iter(other) for key, other in zip(counts, thing)}
yield [next(q[k]) for k in seq]
for t in g(d, c):
print(t)
It looks like you're looking for some way to programmatically call itertools.product
from itertools import product
d = {'a': [0,1,2],
'b': [3,4,5]}
c = ['aab', 'abb', 'aaa']
for s in c:
print(list(product(*[d[x] for x in s])))
I'd like to construct a (n,n)-array from a one dimensional array, where each row is shifted (with wrapping) by one relative to the previous one. The following code does this:
import numpy as np
r = np.array([1, 2, 3, 4, 5])
n = len(r)
MM = np.zeros((n, n), dtype=r.dtype)
for k in range(n):
MM[k, :] = np.roll(r, k)
print(MM)
which results in:
[[1 2 3 4 5]
[5 1 2 3 4]
[4 5 1 2 3]
[3 4 5 1 2]
[2 3 4 5 1]]
Is there a way to do this Numpy faster, i.e., avoiding the for-loop, for large r in Numpy?
Take a look at scipy.linalg.circulant
In [255]: r
Out[255]: array([1, 2, 3, 4, 5])
In [256]: circulant(r).T
Out[256]:
array([[1, 2, 3, 4, 5],
[5, 1, 2, 3, 4],
[4, 5, 1, 2, 3],
[3, 4, 5, 1, 2],
[2, 3, 4, 5, 1]])
or scipy.linalg.toeplitz
In [257]: toeplitz(np.roll(r[::-1], 1), r)
Out[257]:
array([[1, 2, 3, 4, 5],
[5, 1, 2, 3, 4],
[4, 5, 1, 2, 3],
[3, 4, 5, 1, 2],
[2, 3, 4, 5, 1]])