List comprehension for loops Python - python

I use a lot of N dimensional arrays and it gets a pain to have to write such indented code and I know some codes can be replaced with list comprehensions and inline statements. For example:
for x in (0,1,2,3):
for y in (0,1,2,3):
if x < y:
print (x, y, x*y)
can be replaced with:
print [(x, y, x * y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y]
But how could I change the action instead of print to do something else like:
total = x+y
So what I want to do is something like:
[(total+=x+y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y]
However this doesn't work
Is there a smart way to do this rather than:
for x in (0,1,2,3):
for y in (0,1,2,3):
if x < y:
total+=x+y

sum works here:
total = sum(x+y for x in (0,1,2,3) for y in (0,1,2,3) if x < y)

As an alternative to writing loops N levels deep, you could use itertools.product():
In [1]: import itertools as it
In [2]: for x, y in it.product((0,1,2,3),(0,1,2,3)):
...: if x < y:
...: print x, y, x*y
0 1 0
0 2 0
0 3 0
1 2 2
1 3 3
2 3 6
This extends naturally to N dimensions.

Use numpy. This lets you use arrays that add up like vectors:
x = numpy.arange(3)
y = numpy.arange(3)
total = x + y
With the modified question, add a call to sum as well
total = numpy.sum(x+y)

Reduce function directly reduces collective items to single item. You can read more about them here, but this should work for you:
total=reduce(lambda x,y:x+y,range(4))
or
total=reduce(lambda x,y:x+y,(0,1,2,3))

Another possibility is:
for x,y in ((x,y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y):
print (x, y, x * y)
In this way you can iterate over anything you'd use in a list comprehension without actually creating the comprehended list (if you get my meaning ;) If comprehended list is big, maybe so big it saturates or even doesn't fit in memory, that's quite handy..

Related

Understanding quantifiers in z3

I'm trying to understand this example:
solve([y == x + 1, ForAll([y], Implies(y <= 0, x < y))])
but after reading the explanation I still don't understand it.
How do you read this?
what is the meaning of []?
My wrong interpretation of this is.
"Given the theorem y == x + 1. Does it hold for all y such that Implies(y <= 0, x < y)?"
With this interpretation if I use y = 0 and x = -1 every constraint (Implies(y <= 0, x < y) is true since y <= 0 and x < y) is respected, but If I run this I find out that it's not solvable.
Do you have any hits to how to understand this topic?
Looks like there're a couple of confusions here. Let's first sort out binding: In a quantifier context, the variable is independent, i.e., it can be renamed with no change to the semantics. So, your original:
from z3 import *
x, y = Ints('x y')
solve([y == x + 1, ForAll([y], Implies(y <= 0, x < y))])
is exactly equivalent to:
from z3 import *
x, y, z = Ints('x y z')
solve([y == x + 1, ForAll([z], Implies(z <= 0, x < z))])
Note that we replaced the y in the "scope" of ForAll to z, but left the one in the first conjunct untouched. You can only rename within the scope of ForAll (or Exist), not outside of it.
And both of these equivalent expressions are unsatisfiable. Why? The first conjunct is easy to satisfy; just pick an arbitrary x, and set y to be x+1 and you're done. It's the second conjunct that's unsatisfiable. Because, no matter which x you choose to satisfy the first, you can always find a z that's less than that x (just pick min(0, x-1)), and the quantified formula becomes False for that assignment. And hence there are no solutions.
Now, let's consider the variant you had in your comments, with x > z:
from z3 import *
x, y, z = Ints('x y z')
solve([y == x + 1, ForAll([z], Implies(z <= 0, x > z))])
Again, the first conjunct is easy to satisfy. And this time, so is the second, because you can pick a positive x, and that will be greater than all z's so long as z <= 0, and thus the implication is always true. And that's exactly what z3 is telling you, when it gives you the satisfying assignment:
[x = 2, y = 3]
Note that there's nothing in this assignment regarding the variable z. You cannot really give a model for a universally quantified formula; by definition it is true for all values of z.
Hope this clears things up.
[] is a Python list; the outer one is a list of constraints (representing a conjunction) and the one in the ForAll is a list of constants to bind.
Note that the same constant name can be re-used. In this case, y in y == x + 1 is a global existential and the y in the ForAll is a universally bound variable which also has the name y.

The simple and elegant way to express multiple for loop in python?

I have below code, would like to know what is the best simple and elegant way to express multiple for loop?
for x in range (10):
for y in range (10):
for z in range(10):
if x+y+z=10:
print (x,y,z)
Thanks in advance!
from itertools import product
for x, y, z in product(range(10), range(10), range(10)):
if x + y + z == 10:
print(x, y, z)
To remove range(10) duplication use this:
for x, y, z in product(range(10), repeat=3):
EDIT: as Tomerikoo pointed out - in this specific case the code will be more flexible if you don't unpack the tuple:
for numbers in product(range(10), repeat=3):
if sum(numbers) == 10:
print(*numbers)

Python 2.7 reduce lambda statement conversion to list comprehension

I was examining a code written in python but I got confused with the following line.
return ( reduce(lambda x, y: x + y[0],myList, 0)/len(Actions), )
This code takes x and y as an input sums x and y's first element. After that I think it reduces myList to the value of x+y[0] . How can I accomplish this with using list comprehension instead of using lambda.
The part that corresponds well to a list comprehension is what the reducing function does with its second argument y:
tmp = [ y[0] for y in myList ]
The reducing function then combines this list one element at a time with the "accumulator" x:
x = 0 # The third argument to reduce
tmp = [ y[0] for y in myList ]
for y in tmp:
x += y
or more simply
x = 0
for y in myList:
x += y[0]
or, as you have probably recognized by now
sum(y[0] for y in myList)

How can I fix this algorithm?

I am trying to create a function in Python. This function should be able to create a list of whole numbers less than or equal to the number provided. I've created an empty list, a variable called y and a while loop. In this while loop, as long as y <= x, the results of the subsequent equations are appended to the empty list, and y increments by 1. However, when I call this function, I get a list with only one element. How can I fix this?
def fff(x):
numbers = []
y = 2
while(y <= x):
x = x - (x - y)
numbers.append(x)
y += 1
return numbers
>>> fff(10)
[2]
That function already exists, more or less.
Python 2
def fff(x):
return range(1,x+1)
Python 3
def fff(x):
return list(range(1,x+1))
If you look at this line x = x - (x - y) and think of your inputs, you will see the problem. if x initially equals 10, then x - (x - y) equals 2, and y will equal 3, therefore breaking out of your loop.
If you are trying to mimic the range function then this is how you would do it:
def fff(x):
numbers = []
y = 1
while(y <= x):
numbers.append(y)
y += 1
return numbers

Python: for statement behavior

My question concerns the output of this statement:
for x in range(4), y in range(4):
print x
print y
Results in:
[0, 1, 2, 3]
2
True
2
It seems there is a comparison involved, I just can't figure out why the output is structured like this.
My guess is that you're running this from an interactive console, and already had y defined with a value of 2 (otherwise, you'd get NameError: name 'y' is not defined). That would lead to the output you observed.
This is due to for x in range(4), y in range(4): actually being equivalent to the following when evaluated:
for x in (range(4), y in range(4)):
which reduces to...
for x in ([0,1,2,3], 2 in range(4)):
which again reduces to...
for x in ([0,1,2,3], True):
This then results in 2 iterations of the for loop, since it iterates over each element of the tuple:
x = [0,1,2,3]
x = True.
(And of course, y is still 2.)
You've created a weird, weird thing there.
>>> y = 2
>>> range(4), y in range(4)
([0, 1, 2, 3], True)
The y in range(4) is a membership test.
The range(4), y in range(4) is a pair of items; a tuple.
The variable x is set to range(4), then the result of y in range(4).
The variable y is just laying around with a value; it is not set by the for statement.
This only works hacking around on the command line typing random stuff with y left laying around.
This isn't sensible Python code at all.
[And yes, the word in has two meanings. So do ()'s and several other pieces of syntax.]
You seem to have y defined prior to running this code. What you're iterating over is a two-item tuple: first item is range-generated list, second is True, which is result of the y in range(4):
>>> y = 2
>>> for x in range(4), y in range(4):
print x, 'x'
print y, 'y'
[0, 1, 2, 3] x
2 y
True x
2 y
What I suspect you were trying to do is to iterate over two variables from two lists. Use zip for this.
Dav nailed down perfectly why the syntax you wrote doesn't work.
Here are the syntaxes that do work for what you're probably trying to do:
If you want all 4 x 4 combinations for x and y, you want 2 nested loops:
for x in range(4):
for y in range(4):
print x, y
Or if you really want to use one loop:
import itertools
for (x, y) in itertools.product(range(4), range(4)):
print x, y
itertools.product() generates all possible combinations:
This is less readable than 2 loops in this simple case, but the itertools module has many other powerful functions and is worth knowing...
If you want x and y to advance in parallel over two sequences (aka "lock-step" iteration):
for (x, y) in zip(range(4), range(4)):
print x, y
# `zip(range(4), range(4))` is silly since you get x == y;
# would be useful for different sequences, e.g.
# zip(range(4), 'abcd')
[Background: The name zip comes from Haskell; think about how a Zipper takes one tooth from here and one from there:
zip() cuts off to the length of the shortest sequence; the itertools module has other variants...]

Categories

Resources