What does the following expression produce as a value:
[(x, x*y) for x in range(2) for y in range(2)]
[(0,0), (0,1), (1,0), (1,1)]
[0, 1, 2]
[(0,0), (1,0), (0,0), (1,1)]
[(0,0), (0,0), (1,0), (1,1)]
None of the above
The answer is 4, but I don't understand why.
Assuming python 2.
range(2) returns the list [0, 1]
[(x, x*y) for x in [0, 1] for y in [0,1]]
Thus x and y will be all combinations of the lists [0, 1] and [0, 1]
[(x, x*y) for (x, y) in [(0, 0), (0, 1), (1, 0), (1, 1)]]
x y x*y (x, x*y)
0 0 0 (0, 0)
0 1 0 (0, 0)
1 0 0 (1, 0)
1 1 1 (1, 1)
read as:
for x in range(2): # 0,1
for y in range(2): # 0,1
(x, x*y)
Read this as
list = [];
for x in range(2):
for y in range(2):
list.append((x, x*y))
Basically it will iterate 4 times with the following X,Y values
X=0, Y=0
X=0, Y=1
X=1, Y=0
X=1, Y=1
Zero times anything will always be zero, so you get your 4 arrays
First Index = 0, 0*0
Second Index = 0, 0*1
Third Index = 1, 1*0
Fourth Index = 1, 1*1
Nested list comprehensions work in the same way as if you had written for loops like that.
So your example list comprehension works like this generator function:
def example():
for x in range(2):
for y in range(2):
yield (x, x*y)
Related
from itertools import combinations
def n_length_combo(arr, n):
# using set to deal
# with duplicates
return list(combinations(arr, n))
# Driver Function
if __name__ == "__main__":
arr = '01'
n = 3
print (n_length_combo([x for x in arr], n) )
Expected Output
wanted 3 combination of 0 and 1 .Tried with above example but it is not working
You're looking for a Cartesian product, not a combination or permutation of [0, 1]. For that, you can use itertools.product.
from itertools import product
items = [0, 1]
for item in product(items, repeat=3):
print(item)
This produces the output you're looking for (albeit in a slightly different order):
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(1, 1, 1)
Suppose I have a list of 10 elements [a, b, c, d, e, f, g, h, i, j] and I can multiply each element by 0, 1, 2, -1, -2.
The total of the multiplication factors I use must be equal to zero. Ie if I multiply five numbers by -1 I must multiply the other five by 1, or I can multiply a by 2, b and c by -1 and the rest by 0.
I want to find the list resulting from this operation that has the largest sum.
How can I go about coding this in python?
I've tried coding every single iteration of [2, 1, 0, -1, -2] and deleting the lists that do not add to 0 and then multiplying by the original list, however I got stuck.
You can sort the list, scan it from the ends towards the center, assigning 2 to the larger element and -2 to the smaller.
def baby_knapsack(xs):
xs = sorted(xs, reverse=True)
res = list()
n = len(xs)
for i in range(n//2):
res.extend(((xs[i], 2), (xs[-1-i], -2)))
if n % 2 == 1:
res.append((xs[n//2], 0))
return res
xs = [-10, -5, 0, 5, 10, 15]
# In [73]: q.baby_knapsack(q.xs)
# Out[73]: [(15, 2), (-10, -2), (10, 2), (-5, -2), (5, 2), (0, -2)]
This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 3 years ago.
I am attempting to create a 4d array and assign variables to each of the cells.
Typically I would use four "for loops" but this is very messy and takes up a lot of space.
What i'm currently doing:
for x in range(2):
for y in range(2):
for j in range(2):
for k in range(2):
array[x,y,j,k] = 1 #will be a function in reality
I've tried using list comprehension but this only creates the list and does not assign variables to each cell.
Are there space-efficient ways to run through multiple for loops and assign variables with only a few lines of code?
Assuming you've already created an empty (numpy?) array, you can use itertools.product to fill it with values:
import itertools
for x, y, j, k in itertools.product(range(2), repeat=4):
arr[x,y,j,k] = 1
If not all of the array's dimensions are equal, you can list them individually:
for x, y, j, k in itertools.product(range(2), range(2), range(2), range(2)):
arr[x,y,j,k] = 1
You may however be wondering how itertools.product does the trick. Or maybe you want to encode a different transformation in your recursive expansion. Below, I'll share one possible solution using Python's generators -
def product (*iters):
def loop (prod, first = [], *rest):
if not rest:
for x in first:
yield prod + (x,)
else:
for x in first:
yield from loop (prod + (x,), *rest)
yield from loop ((), *iters)
for prod in product ("ab", "xyz"):
print (prod)
# ('a', 'x')
# ('a', 'y')
# ('a', 'z')
# ('b', 'x')
# ('b', 'y')
# ('b', 'z')
Because product accepts a a list of iterables, any iterable input can be used in the product. They can even be mixed as demonstrated here -
print (list (product (['#', '%'], range (2), "xy")))
# [ ('#', 0, 'x')
# , ('#', 0, 'y')
# , ('#', 1, 'x')
# , ('#', 1, 'y')
# , ('%', 0, 'x')
# , ('%', 0, 'y')
# , ('%', 1, 'x')
# , ('%', 1, 'y')
# ]
We could make a program foo that provides the output posted in your question -
def foo (n, m):
ranges = [ range (m) ] * n
yield from product (*ranges)
for prod in foo (4, 2):
print (prod)
# (0, 0, 0, 0)
# (0, 0, 0, 1)
# (0, 0, 1, 0)
# (0, 0, 1, 1)
# (0, 1, 0, 0)
# (0, 1, 0, 1)
# (0, 1, 1, 0)
# (0, 1, 1, 1)
# (1, 0, 0, 0)
# (1, 0, 0, 1)
# (1, 0, 1, 0)
# (1, 0, 1, 1)
# (1, 1, 0, 0)
# (1, 1, 0, 1)
# (1, 1, 1, 0)
# (1, 1, 1, 1)
Or use destructuring assignment to create bindings for individual elements of the product. In your program, simply replace print with your real function -
for (w, x, y, z) in foo (4, 2):
print ("w", w, "x", x, "y", y, "z", z)
# w 0 x 0 y 0 z 0
# w 0 x 0 y 0 z 1
# w 0 x 0 y 1 z 0
# w 0 x 0 y 1 z 1
# w 0 x 1 y 0 z 0
# w 0 x 1 y 0 z 1
# w 0 x 1 y 1 z 0
# w 0 x 1 y 1 z 1
# w 1 x 0 y 0 z 0
# w 1 x 0 y 0 z 1
# w 1 x 0 y 1 z 0
# w 1 x 0 y 1 z 1
# w 1 x 1 y 0 z 0
# w 1 x 1 y 0 z 1
# w 1 x 1 y 1 z 0
# w 1 x 1 y 1 z 1
Because product is defined as a generator, we are afforded much flexibility even when writing more complex programs. Consider this program that finds right triangles made up whole numbers, a Pythagorean triple. Also note that product allows you to repeat an iterable as input as see in product (r, r, r) below
def is_triple (a, b, c):
return a * a + b * b == c * c
def solver (n):
r = range (1, n)
for p in product (r, r, r):
if is_triple (*p):
yield p
print (list (solver (20)))
# (3, 4, 5)
# (4, 3, 5)
# (5, 12, 13)
# (6, 8, 10)
# (8, 6, 10)
# (8, 15, 17)
# (9, 12, 15)
# (12, 5, 13)
# (12, 9, 15)
# (15, 8, 17)
For additional explanation and a way to see how to do this without using generators, view this answer.
1How would I traverse an array from the centre outwards, visiting each cell only once?
I can do it with a breadthfirst traversal by finding unvisited neighbours, but how could I do it with some kind of edit-distance traversal? I've been trying to figure it out on paper, but can't wrap my head around it.
eg, in an array
[
[5 6 8 9 0]
[1 2 4 5 6]
[5 4 0 2 1]
[1 2 3 4 5]
[1 2 3 4 5]]
starting from the zero in the centre, we would visit the 4 at [1][2] then the 2 at [2][3] then the 3 at [3][2] then the 4 at [2][1] then the 8 at [0][2]and then the 5 at the [1][3] etc etc
I've tried this, which gets close, but misses some.
def traversalOrder(n): #n is size of array (always square)
n = n/2
t = []
for k in range(1,n+1):
t += [(i,j) for i in range(n-k,n+k+1) for j in range(n-k,n+k+1) if (i,j) not in t and (i-j == k or j-i == k) ]
I have an open source library pixelscan that does this sort of spatial pattern traversal on a grid. The library provides various scan functions and coordinate transformations. For example,
x0, y0, r1, r2 = 0, 0, 0, 2
for x, y in ringscan(x0, y0, r1, r2, metric=manhattan):
print x, y
where
x0 = Circle x center
y0 = Circle y center
r1 = Initial radius
r2 = Final radius
metric = Distance metric
produces the following points in a diamond:
(0,0) (0,1) (1,0) (0,-1) (-1,0) (0,2) (1,1) (2,0) (1,-1) (0,-2) (-1,-1) (-2,0) (-1,1)
You can apply a translation to start at any center point you want.
It seems that you could use some sort of priority queue to sort the elements based on an edit distance, like you suggested. While my edit distance doesn't give you the EXACT order you are looking for, it might be a starting point. I used heapq.
import heapq
grid = [
[5, 6, 8, 9, 0],
[1, 2, 4, 5, 6],
[5, 4, 0, 2, 1],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
rows = len(grid)
cols = len(grid[0])
heap_list = []
for row in xrange(rows):
for col in xrange(cols):
edit_distance = abs(row - rows/2) + abs(col - cols/2)
#heappush(heap, (priority, object))
heapq.heappush(heap_list, (edit_distance, grid[row][col]))
for i in xrange(len(heap_list)):
print heapq.heappop(heap_list)
# prints (distance, value)
# (0, 0)
# (1, 2)
# (1, 3)
# (1, 4)
# (1, 4)
# (2, 1)
# etc...
I think the easiest way to do this is with three nested loops. The outer most loop is over the expanding radiuses of your diamonds. The next loop is the four sides of a given diamond, described by a starting point and a vector the move along. The innermost loop is over the points along that side.
def traversal(n):
h = n//2
yield h, h # center tile doesn't get handled the by the loops, so yield it first
for r in range(1, n):
for x0, y0, dx, dy in [(h, h-r, 1, 1),
(h+r, h, -1, 1),
(h, h+r, -1, -1),
(h-r, h, 1, -1)]:
for i in range(r):
x = x0 + dx*i
y = y0 + dy*i
if 0 <= x < n and 0 <= y < n:
yield x, y
If n is always odd, you can improve the performance of the inner loop a bit by limiting i rather than computing all the points and doing bounds tests to skip the ones that are outside your grid. Switching range(r) to range(max(0, r-h), max(r, h+1)) and getting rid of the if before the yield should do it. I'll leave the version above however, since its logic is much more clear.
So here's the issue, I have a 2-d list of characters 'T' and 'F', and given coordinates I need to get all of its neighbors. I have this:
from itertools import product, starmap
x, y = (5, 5)
cells = starmap(lambda a, b: (x + a, y + b), product((0, -1, +1), (0, -1, +1)))
from determining neighbors of cell two dimensional list But it will only give me a list of coordinantes, so i still fetch the values afterwords. I'd like the search and retrieval done in one step, so findNeighbors(5,5) would return F,T,F,F,... instead of (5, 4), (5, 6), (4, 5), (4, 4)... Is there a fast way of doing this? The solutin can include a structure other than a list to hold the initial information
The following should work, with just a minor adaptation to the current code:
from itertools import product, starmap, islice
def findNeighbors(grid, x, y):
xi = (0, -1, 1) if 0 < x < len(grid) - 1 else ((0, -1) if x > 0 else (0, 1))
yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
return islice(starmap((lambda a, b: grid[x + a][y + b]), product(xi, yi)), 1, None)
For example:
>>> grid = [[ 0, 1, 2, 3],
... [ 4, 5, 6, 7],
... [ 8, 9, 10, 11],
... [12, 13, 14, 15]]
>>> list(findNeighbors(grid, 2, 1)) # find neighbors of 9
[8, 10, 5, 4, 6, 13, 12, 14]
>>> list(findNeighbors(grid, 3, 3)) # find neighbors of 15
[14, 11, 10]
For the sake of clarity, here is some equivalent code without all of the itertools magic:
def findNeighbors(grid, x, y):
if 0 < x < len(grid) - 1:
xi = (0, -1, 1) # this isn't first or last row, so we can look above and below
elif x > 0:
xi = (0, -1) # this is the last row, so we can only look above
else:
xi = (0, 1) # this is the first row, so we can only look below
# the following line accomplishes the same thing as the above code but for columns
yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
for a in xi:
for b in yi:
if a == b == 0: # this value is skipped using islice in the original code
continue
yield grid[x + a][y + b]