Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 13 days ago.
Improve this question
I'm trying to practice using list comprehensions in Python.
I set myself the task of making a list based off domino pieces that have a 5 on them. That is, the result should be:
[[5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6]]
I'm following a course, but the examples so far only show how to create these types of nested lists with ascending numbers using ranges, like [[1,2,3], [1,2,3]].
I tried this code:
x = [val for val in range(0,7)]
Fives = [[5,x] for pieces in range(0,7)]
print(Fives)
But I get a wrong result:
[[5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]], [5, [0, 1, 2, 3, 4, 5, 6]]]
What is wrong, and how do I fix it?
You're dangerously close to an XY Problem here!
Switching approaches, in order to create all the possible domino pieces, instead you can use itertools.permutations()
>>> list(permutations(range(6+1), 2))
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 0), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 0), (2, 1), (2, 3), (2, 4), (2, 5), (2, 6), (3, 0), (3, 1), (3, 2), (3, 4), (3, 5), (3, 6), (4, 0), (4, 1), (4, 2), (4, 3), (4, 5), (4, 6), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 6), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5)]
However, if instead of generating the collection directly, you must iterate through an inner list, instead iterate over it by directly using a form like for value in collection: (as all common collections are iterable - docs on iterator and sequence types)
values = list(range(7)) # 0,1,2,3,4,5,6
results = []
for val_upper in range(7): # or your original list as they're the same!
for val_lower in values: # iterate over collection, getting each in turn
results.append([val_upper, val_lower])
or when the upper (leftmost?) value is always 5 (perhaps what you really expected)
>>> values = list(range(6+1))
>>> [[5, x] for x in values] # iterates over values
[[5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6]]
Finally, if you have a small collection (as is the case here) and only wanted values that start with 5, you could comprehend your collection back filtering it as you go
..in this small case, it's not particularly elegant, but it's far more useful when generating a collection which isn't mathematically perfect or has specialized filtering requirements
>>> list(domino for domino in permutations(range(6+1), 2) if domino[0] == 5)
[(5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 6)]
a = []
def make_squares(arr, length, nums):
if not nums:
print(arr)
a.append(arr)
return
r = 0
while r < len(arr) and len(arr[r]) == length:
r += 1
for i in nums:
nums.remove(i)
arr[r].append(i)
make_squares(arr, length, nums)
nums.append(i)
arr[r] = arr[r][:-1]
make_squares([[] for i in range(3)], 3, [i+1 for i in range(3**2)])
print(a)
I'm trying to use the above code to create nxn matrices each with a permutation of the numbers i+1...n^2. I have printed every matrix that gets appended to a and they appear correct, but when I print a in the end, I get [[[], [], []], [[], [], []], ...]. It doesn't make any sense to me.
The expected result would be
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[1, 2, 3], [4, 5, 6], [7, 9, 8]], ...]
The order may not be the same as in your expected result, but this does the trick with the standard library itertools module:
import itertools
def make_squares(w):
size = w * w
for perm in itertools.permutations(range(1, size + 1)):
# "grouper" from the itertools recipe list
yield list(itertools.zip_longest(*[iter(perm)] * w))
for square in make_squares(3):
print(square)
prints
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
[(1, 2, 3), (4, 5, 6), (7, 9, 8)]
[(1, 2, 3), (4, 5, 6), (8, 7, 9)]
[(1, 2, 3), (4, 5, 6), (8, 9, 7)]
[(1, 2, 3), (4, 5, 6), (9, 7, 8)]
[(1, 2, 3), (4, 5, 6), (9, 8, 7)]
[(1, 2, 3), (4, 5, 7), (6, 8, 9)]
[(1, 2, 3), (4, 5, 7), (6, 9, 8)]
[(1, 2, 3), (4, 5, 7), (8, 6, 9)]
[(1, 2, 3), (4, 5, 7), (8, 9, 6)]
[(1, 2, 3), (4, 5, 7), (9, 6, 8)]
[(1, 2, 3), (4, 5, 7), (9, 8, 6)]
[(1, 2, 3), (4, 5, 8), (6, 7, 9)]
[(1, 2, 3), (4, 5, 8), (6, 9, 7)]
[(1, 2, 3), (4, 5, 8), (7, 6, 9)]
...
I'm trying to use numpy to find configurations of rows in a matrix such that summing the columns of the rows will result in the same value. As an example, for the matrix/array
[[0,0,0,1],
[1,0,1,0],
[1,1,0,0],
[0,1,0,0]]
I would like to have the first, second, and last row as output, because
0,0,0,1
1,0,1,0
0,1,0,0 +
-------
= 1,1,1,1
Is there any tools built into numpy that would assist me in acquiring this?
One solution is to enumerate the power set of rows and then check each possible subset of rows for the summation condition. For matrices with a large number of rows, this is likely to be quite slow.
Use the standard itertools recipe for the power set:
from itertools import chain, combinations
def powerset(iterable):
xs = list(iterable)
return chain.from_iterable(combinations(xs, n) for n in range(len(xs) + 1))
then I show a working example with some synthetic data:
In [79]: data
Out[79]:
array([[0, 1, 1],
[0, 0, 1],
[1, 0, 1],
[0, 1, 1],
[0, 0, 0],
[0, 1, 0],
[1, 1, 1],
[1, 1, 0],
[1, 1, 1],
[0, 1, 0]], dtype=int32)
In [80]: def is_constant(array):
...: return (array == array[0]).all()
...:
In [81]: solution = []
In [82]: for candidate in powerset(range(len(data))):
...: if candidate and is_constant(data[candidate, :].sum(axis=0)):
...: solution.append(candidate)
...:
Which shows, for example:
In [83]: solution
Out[83]:
[(4,),
(6,),
(8,),
(1, 7),
(2, 5),
(2, 9),
(4, 6),
(4, 8),
(6, 8),
(0, 2, 7),
(1, 4, 7),
(1, 6, 7),
(1, 7, 8),
(2, 3, 7),
(2, 4, 5),
(2, 4, 9),
(2, 5, 6),
(2, 5, 8),
(2, 6, 9),
(2, 8, 9),
(4, 6, 8),
(0, 2, 4, 7),
(0, 2, 6, 7),
(0, 2, 7, 8),
(1, 2, 5, 7),
(1, 2, 7, 9),
(1, 4, 6, 7),
(1, 4, 7, 8),
(1, 6, 7, 8),
(2, 3, 4, 7),
(2, 3, 6, 7),
(2, 3, 7, 8),
(2, 4, 5, 6),
(2, 4, 5, 8),
(2, 4, 6, 9),
(2, 4, 8, 9),
(2, 5, 6, 8),
(2, 6, 8, 9),
(0, 2, 4, 6, 7),
(0, 2, 4, 7, 8),
(0, 2, 6, 7, 8),
(1, 2, 4, 5, 7),
(1, 2, 4, 7, 9),
(1, 2, 5, 6, 7),
(1, 2, 5, 7, 8),
(1, 2, 6, 7, 9),
(1, 2, 7, 8, 9),
(1, 4, 6, 7, 8),
(2, 3, 4, 6, 7),
(2, 3, 4, 7, 8),
(2, 3, 6, 7, 8),
(2, 4, 5, 6, 8),
(2, 4, 6, 8, 9),
(0, 2, 4, 6, 7, 8),
(1, 2, 4, 5, 6, 7),
(1, 2, 4, 5, 7, 8),
(1, 2, 4, 6, 7, 9),
(1, 2, 4, 7, 8, 9),
(1, 2, 5, 6, 7, 8),
(1, 2, 6, 7, 8, 9),
(2, 3, 4, 6, 7, 8),
(1, 2, 4, 5, 6, 7, 8),
(1, 2, 4, 6, 7, 8, 9)]
and we can verify the solution for a few of these cases:
In [84]: data[(1, 2, 4, 6, 7, 8, 9), :].sum(axis=0)
Out[84]: array([4, 4, 4])
In [85]: data[(0, 2, 4, 6, 7), :].sum(axis=0)
Out[85]: array([3, 3, 3])
To extend this for more specific use cases, you could use itertools.combinations to produce subsets of only a certain size, like subsets of exactly 2 rows or exactly 3 rows, etc.
Or you could just filter out unwanted results (like trivial solutions consisting of one row at a time) from the result set given in my example.
Note you can simplify the function definition of powerset (the one I use is literally just taken from the Python docs about itertools recipes). Instead of passing an iterable that gets converted to a list, you could just pass an integer and skip directly to return the final chain.from_iterable result, and then modify to just pass len(data) as the argument of powerset in my example, like this:
from itertools import chain, combinations
def powerset(N):
"""Power set of integers {0, ..., N-1}."""
xs = list(range(N))
return chain.from_iterable(combinations(xs, n) for n in range(N + 1))
...
for candidate in powerset(len(data)):
...
I have values for a 2-dimensional list:
# 4 x 4, 2-dimensional list
values = [[4, 7, 8],
[1, 3, 4],
[7, 5, 6],
[2, 9, 1]]
I want to create tuples containing all possible permutations of these values (Cartesian product) for each list.
# example for the list at index 0 of values
args0 = [(4, 7, 8), (7, 4, 8), (4, 8, 7), (8, 4, 7), (7, 8, 4), (8, 7, 4)]
Is there an easy way to go about this? I have tried itertools but cannot get it to work with "specific values".
What you want is the permutations of each element in the list, so just map itertools.permutations:
import itertools
values = [[4, 7, 8],
[1, 3, 4],
[7, 5, 6],
[2, 9, 1]]
perms = map(itertools.permutations, values)
for v in perms:
print(list(v))
Result:
[(4, 7, 8), (4, 8, 7), (7, 4, 8), (7, 8, 4), (8, 4, 7), (8, 7, 4)]
[(1, 3, 4), (1, 4, 3), (3, 1, 4), (3, 4, 1), (4, 1, 3), (4, 3, 1)]
[(7, 5, 6), (7, 6, 5), (5, 7, 6), (5, 6, 7), (6, 7, 5), (6, 5, 7)]
[(2, 9, 1), (2, 1, 9), (9, 2, 1), (9, 1, 2), (1, 2, 9), (1, 9, 2)]
Here you have a live example
I have an numpy structure array
import numpy as np
np.array([(0, 1, 1167606000), (0, 1, 1167606005), (0, 1, 1167606008),
(0, 10, 1167606010), (0, 10, 1167606012), (1, 0, 1167606000),
(1, 2, 1167606001), (1, 0, 1167606005), (1, 0, 1167606008),
(2, 1, 1167606001), (2, 3, 1167606002), (3, 2, 1167606002),
(3, 4, 1167606003), (4, 3, 1167606003), (4, 5, 1167606004),
(5, 4, 1167606004), (5, 6, 1167606005), (6, 5, 1167606005),
(6, 7, 1167606006), (7, 6, 1167606006), (7, 8, 1167606007),
(8, 7, 1167606007), (8, 9, 1167606008), (9, 8, 1167606008),
(9, 10, 1167606009), (10, 9, 1167606009), (10, 0, 1167606010),
(10, 0, 1167606012)],
dtype=[('fr', '<i8'), ('to', '<i8'), ('time', '<i8')])
Is there a vectorized way to sort it first by the minimum of 'fr', 'to' and then by 'time'. Another thing is that I want to sort this without making any copies.
Edit:
The sort is not by 'fr', 'to' and 'time', but first by the minimum of 'fr' and 'to' followed by 'time'. The expected answer in the above case is
(0, 1, 1167606000),
(1, 0, 1167606000),
(0, 1, 1167606005),
(1, 0, 1167606005),
(0, 1, 1167606008),
(1, 0, 1167606008),
(0, 10, 1167606010),
(0, 10, 1167606012),
(1, 2, 1167606001),
(2, 1, 1167606001),
(2, 3, 1167606002),
(3, 2, 1167606002),
(3, 4, 1167606003),
(4, 3, 1167606003),
...
You can give an order argument to sort:
a.sort(order=['fr', 'to', 'time'])
Sorting by minimum of two columns:
Using lexsort, you can sort by any set of keys. Here, give it a['time'] and np.minimum(a['to'], a['fr']) (sorts by last item first)
inds = np.lexsort((a['time'], np.minimum(a['to'], a['fr'])))
a = a[inds]
To avoid making a copy of a when you rearrange it, you can use take instead of a = a[inds]
np.take(a, inds, out=a)