0
import itertools
def f(x,y,z,w):
    return ((x and y) or (y and z)) == ((not(x) or w) and (not(w) or z))

for p in itertools.permutations("xyzw"):
    ans = []
    t = [(0,1,1,1), (0,1,0,0), (0,1,0,1)]
    for r in t:
        #ans.append(f(*r))
        #ans.append(f(**dict(zip(p,r))))
    if ans == [1,1,1]:
        print(*p)
        break

If I uncomment ans.append(f(*r)) it outputs nothing, but if I uncomment ans.append(f(**dict(zip(p,r)))) it outputs my answer. Why does that happen?

I'm expecting the same output, but there are different arrays after dict(zip) values.

pmqs
  • 3,066
  • 2
  • 13
  • 22

2 Answers2

0

The reason you're getting different outputs is because the two function calls are not passing the same values to the arguments of f():

  • f(*r) passes positional arguments from the array of tuples t, with the first value being assigned to x, the second to y, the third to z, and the fourth to w. So no matter what p is, you're getting ans = [f(0,1,1,1), f(0,1,0,0), f(0,1,0,1)].

  • f(**dict(zip(p,r))) passes keyword arguments with the expected keys x, y, z, w, but the order in which the values from the array of tuples t are assigned to x, y, z, w is determined by the current permutation p. For example, on the first iteration of the for loop, with p = ('x', 'y', 'z', 'w'), you'll get ans = [f(x=0,y=1,z=1,=w=1), ...] equivalent to [f(0,1,1,1), ...] as in the positional argument version above, but on a later iteration, with p = ('y', 'x', 'z', 'w') you'll get ans = [f(y=0,x=1,z=1,w=1), ...] (note the inverted assignments of values to x and y) which is equivalent to ans = [f(1,0,1,1), ...].

Jeff
  • 856
  • 7
  • 13
0

Calling f(*r) is similar to calling f(**dict(zip(['x', 'y', 'z', 'w'], r))) [or f(**dict(zip('xyzw',r))), or f(x=r[0], y=r[1], z=r[2], w=r[3])], but p has the argument names shifted around every loop; so you need to zip with p, otherwise you'll be doing the same thing for every p, and the outermost loop becomes entirely redundant.

Driftr95
  • 4,572
  • 2
  • 9
  • 21