While doing some list comprehension exercises, i accidentally did the code below. This ended up printing True/False for all 16 entries on the list.
threes_and_fives =[x % 3 == 0 or x % 5 == 0 for x in range(16)]
print threes_and_fives
After i played with it i was able to get the outcome that I wanted, where it printed the numbers from that list that are divisible by 3 or 5.
threes_and_fives =[x for x in range(16) if x % 3 == 0 or x % 5 == 0]
print threes_and_fives
My questions is why did the first code evaluated to true or false and the other one didn't? I'm trying to get a grasp of python so the more explanations the better :) Thanks!
What you may be missing is that there is nothing special about relational operators in Python, they are expressions like any others, ones that happen to produce Boolean values. To take some examples:
>>> 1 + 1 == 2
True
>>> 2 + 2 == 5
False
>>> [1 + 1 == 2, 2 + 2 == 5]
[True, False]
A list comprehension simply collects expressions involving elements of an iterable sequence into a list:
>>> [x for x in xrange(5)] # numbers 0 through 4
[0, 1, 2, 3, 4]
>>> [x**2 for x in xrange(5)] # squares of 0 through 4
[0, 1, 4, 9, 16]
Your first expression worked just like that, but with the expression producing Booleans: it told Python to assemble a list of Boolean values corresponding to whether the matching ordinal is divisible by 3 or 5.
What you actually wanted was a list of numbers, filtered by the specified condition. Python list comprehensions support this via an optional if clause, which takes an expression and restricts the resulting list to those items for which the Boolean expression returns a true value. That is why your second expression works correctly.
In the following code:
[x % 3 == 0 or x % 5 == 0 for x in range(16)]
The list comprehension is returning the result of x % 3 == 0 or x % 5 == 0 for every value in range(16), which is a boolean value. For instance, if you set x equal to 0, you can see what is happening at every iteration of the loop:
x = 0
x % 3 == 0 or x % 5 == 0
# True
Hope this helps, and happy FizzBuzzing
In your first code sample, you are putting the value of
x % 3 == 0 or x % 5 == 0
into your list. As that expression is evaluated as true or false, you will end up with boolean values in the list.
In the second example, your condition is the condition for including x in the list, so you get the list of numbers which are divisible by 3 or 5. So, the list comprehension statement has to be read as
Include value x from the set {0,1,...,15} where condition (x is divisible by 3 or 5) is met.
EDIT: Fixed the set according to #user4815162342's comment.
The following line is a condition returning True or False:
x % 3 == 0 or x % 5 == 0
So in your first attempt you have put it in your list
This is simply the allowed expression syntax in Python. For a list comprehension, you need ...
Item to appear in the final list
Source of items
Restrictions
The first example you gave evaluates to a Boolean value (True / False).
The second one says to put the value of x into the list, with the restriction of divisibility.
Related
Im asked to filter a function. The specific term is:
Create the variable filter_t3 that contains the filter function to create a generator for all numbers from 1 to 101 (both inclusive) that are dividable by 7, 13, or 42.
Then, use the list() function to create a list with the name result_t3 which contains the filtered elements (the ones that match the expression above).
Hint: Use a lambda function in the expression parameter of filter.
Thanks for the help!!
Stay safe and sound!
First, you assign a function that returns a bool when the number is divisible by the ones you have and store it in the lambda, I'm sure there are better ways to do this but this one works fine.
Then, we create the list from 1 to 101 which I named num_list.
Finally, we apply the filter function to the list and store the result in a new list called result_t3.
filter_t3 = lambda x: (x % 7 == 0 or x % 13 == 0 or x % 42 == 0)
num_list = list(range(1, 102))
result_t3 = filter(filter_t3, num_list)
print(num_list)
print(result_t3)
I'd encourage you to read about the filter function and how to use lambdas with them.
EDIT: Since range is only inclusive to the first number, I changed 101 to 102 after the comma.
EDIT2: I need to learn how to read, you said dividable by x OR y, changed the lambda to reflect that.
I guess that's what you are looking for:
filter_t3 = filter(lambda x: x % 7 == 0 or x % 13 == 0 or x % 42 == 0,range(1, 102))
result_t3 = list(filter_t3)
This question already has answers here:
Identify if list has consecutive elements that are equal
(8 answers)
Closed 2 years ago.
Given a list of integers, for example:
lst = [3,3,6,5,8,3,4,5]
I am then using list comprehension to find out at which index the number 3 appears in this list:
[i for i, x in enumerate(lst) if x == 3]
But now I cannot work out how to see if the number 3 is sitting next to another 3 and return this as True
You can use zip() to loop over the data pairwise:
any(a == b == 3 for a, b in zip(lst, lst[1:]))
The chained comparison then to checks to see if both a and b are equal to 3. The function any() checks to see if any of those changed comparisons are true.
FWIW, another way to loop pairwise() is shown in the itertools recipes section of the docs.
Hope this helps :-)
But now I cannot work out how to see if the number 3 is sitting next to another 3 and return this as True
Well since your result is a list of all indices where a 3 can be found, you can just check any two consecutive indices and see if they differ by just 1.
Sadly "windowing" iterators still are not part of the standard library, but replicating them is easy enough:
indices = [3,3,6,5,8,3,4,5]
for i, j in zip(indices, indices[1:]):
...
Here is another pretty straight forward way to do it (kinda over-commplicated)
def check(index, lst):
if index > 0 and lst[index] == lst[index - 1] and lst[index] == 3:
return True
if index < len(lst) and lst[index] == lst[index + 1] and lst[index] == 3:
return True
return False
lst = [3,3,6,5,8,3,4,5]
for index in range(len(lst)):
print(check(index, lst))
Output:
True
True
False
False
False
False
False
I'm a newbie to Python and one of our practice examples is in the code below but there is no feedback on what the code is doing. The question in the exercise asks "How many times is P printed out" I've provided the output below.
From what I understand on my own, the length of s is 6 and the range is 0 to 5 but since we are saying "range(len(s))" are we basically asking the loop to run 6 times?
Also, can someone help me understand the print(s[idx % 2])? How does the print statement generate the output shown below? If I were to change it to print(s[ 0:2 ] then I would be given "pypypy" horizontally which is different.
Thank you for the help.
s = "python"
for idx in range(len(s)):
print(s[idx % 2])
Output
p
y
p
y
p
y
Strings in Python are arrays of bytes representing unicode characters. However, Python does not have a character data type, a single character is simply a string with a length of 1. Square brackets can be used to access elements of the string. Therefore you can get the character at position 1 (remember that the first character has the position 0) via the following code snippet, e.g:
a = "Hello, World!"
print(a[1]) // e
print(a[2]) // l
Now looking at why your code outputs what it does (second part of your question). Recall that % is the modulo operator.
In the first run, idx = 0. So your statement becomes:
print(s[0 % 2]) = print(s[0]) = 'p' -> first letter of s.
Next idx = 1. So your statement becomes:
print(s[1 % 2]) = print(s[1]) = 'y' -> second letter of s.
Next idx = 2. So your statement becomes:
print(s[2 % 2]) = print(s[0]) = 'p' -> first letter of s.
And so on, 6 times (idx takes values of 0, 1, 2, 3, 4, 5).
P.S. Commenting on your comment regarding setting print(s[ 0:2 ]) - this is known as string slicing (essentially call out a range of characters from the string) - [0:2] means you are starting at index 0 and extend up to but not including index 2, so 'py'.
are we basically asking the loop to run 6 times?
Yes
can someone help me understand the print(s[idx % 2])?
Yes
How does the print statement generate the output shown below?
The % operator is the modulo operator. It gives the remainder of a division. For the range in question, the results are
0 divided by 2 is 0 with a remainder of 0
1 divided by 2 is 0 with a remainder of 1
2 divided by 2 is 1 with a remainder of 0
3 divided by 2 is 1 with a remainder of 1
4 divided by 2 is 2 with a remainder of 0
5 divided by 2 is 2 with a remainder of 1
As you can see, the remainder toggles between 0 and 1.
Indexing the string will thus result in s[0] which is p and s[1] which is y.
I can't understand how this condition behind the % works
for i in range(1,6):
print "pet%d" % (i == 1 and 2 or 4)
this part (i == 1 and 2 or 4) is what I cant understand. As far as I understand it does the same as a
if i == 1:
i = 2
else:
i = 4
but how does the (i == 1 and 2 or 4) work especially with the %d % i formatting?
Read it as 2 if i == 1 else 4 using the python a if b else c or if i == 1 then 2 else 4
It gives 4 unless i == 1 returns true, then it gives 2:
pet2
pet4
pet4
pet4
pet4
This sort of boolean (ab)use is common in shell scripts:
Evaluating the boolean goes as follows:
If i == 1 is True, then we must test what is on the other side of the and. 2 is also true, so we exit early (as the or is already known to be true, returning the last value 2.
If i == 1 is False, we skip the other side of the and and evaluate the other side of the or, which is 4. 4 is true, so we return 4.
What you have is an example of short-circuiting with and and or.
We can add some parens to see how the expression is evaluated:
(((i == 1) and 2) or 4)
or: only evaluates the second argument if the first one is False
and: only evaluates the second argument if the first one is True
Which makes 2 the result of the evaluation when i is 1 (since 2 is truthy and the second operand of the or will not be evaluated), and 4 otherwise (since a False in the first operand of the and means the second operand of the or will be returned).
About conditional statement:
In Python, some values can be evaluated kinda like True and False even if they are not boolean values:
For instance:
if []:
print "this branch is never reached since it evaluates to False"
print "due to the empty list"
if 0:
print "same thing here"
(More info about how some data types are evaluated in a boolean expression here: http://getpython3.com/diveintopython3/native-datatypes.html#booleans)
Now, back to the following statement:
(i == 1 and 2 or 4)
Here we have a boolean expression as well. Dissecting the expression, we have the following:
(i == 1 and 2 or 4)
((i == 1) and 2) or (4) # This is the order of evaluation
Since 2 and 4 are not 0, they will always evaluate to True
Now, understanding the output: The output will be always 4 if i is different than 1.
The reason for this is because if i == 1 the returned value is 2. The value 2 is returned because it is not necessary to evaluate the whole expression 2 or 4 since the first part is evaluated to True.
On the other hand, if i is not 1, the value 4 has to be evaluated. Because 4 is not zero, it is evaluated to True.
This is why the output is always 4 if i is different than 1
About the "ternary" operator:
Python does not have a ternary operator like in Java/C/C++ (?:) but you have a similar effect using if-else:
# value a = <value if condition is true> if <condition> else <other value>
# Example
>>> a = 2 if 1 < 10 else 0
>>> a
2
Therefore, if you wanted to print values from the range function, you should use the following:
for i in range(1,6):
print "pet%d" % i
Or maybe, printing A for even numbers and B for odd numbers:
for i in range(1,6):
print "pet%s" % ("A" if i % 2 == 0 else "B")
I might be wrong, but I know in javaScript when you say i == 1 and 2 or 4 it evaluates from left to right.
Thus the computer will determine if i == 2, and if it does, it will have a temp val of bits set to 1, and take that flag and bitwise AND it with 2, resulting in the value 2. Since the next expression is an OR, it will not compute that since the condition is true regardless, and the "and" operator short circuits. Thus 2 will print.
However if i != 2, then the first part will evaluate to false, and have a temp val of all 0 bits. Then, the or with 4 will change the value to 4 (a bitwise 0 with 4 returns 4), and so 4 will print.
I hope this makes sense! Let me know if you have any other questions.
Let's say I have a list like:
my_list = range(10)
And I want to count how many even numbers there are in the list. Note that I am not interested with the values, I just want the count of them. So I can:
len( [0 for i in my_list if i % 2 == 0] ) # Method 1
len( [i for i in my_list if i % 2 == 0] ) # Method 2
len( [_ for i in my_list if i % 2 == 0] ) # Method 3
Is any of the above methods better than others from the speed or memory perspectives?
Actually I don't even need to construct the list, but I don't want to:
counter = 0
for item in my_list:
if item % 2 == 0:
counter += 1
So, which one is a good way of counting with generators?
PS: The list in my case has more memory-heavy items, that is why I want to optimize if possible.
Use none of the above. Use sum() and a generator expression:
sum(i % 2 == 0 for i in mylist)
In Python, the bool boolean type is a subclass of int and True has an integer value of 1, False has 0, so you can sum a series of True and False results.
The sum()-with-generator expression only has to keep one boolean in memory at a time, no intermediary list has to be produced and kept around just to calculate a length.
Alternatively, stick to filtering and sum 1 literals:
sum(1 for i in mylist if i % 2 == 0)
This results in fewer objects needing to be added up still.