Why do I get the following behavior? I expect the result to be just 1.
In [77]: a = 1
In [78]: [a if a else s for s in [0, 1,0]]
Out[78]: [1, 1, 1]
Since a is not empty the value in the list should be a only.
Here else should only be executed when a is None.
EDIT: I want to insert a in the list if a is not None, else insert s in the list.
That's normal behavior. You're iterating through a list that contains three numbers. if a is always true. So, a if a is executed three times. That's why you get three a's added to the list.
Regarding your latest edit:
I want to insert a in the list if a is not None, else insert s in the list.
Okay, then you do this:
res=[]
if a:
res.append(a)
else:
for s in [0,1,0]:
res.append(s)
a if a else s evaluates to a if a is truthy. a never changes, so no matter what you iterate through in the list comprehension, you will get the same thing: a list of as as long as what you are iterating through.
Maybe you want this?
[a] if a else [0, 1, 0]
This expression will evaluate to a list with a in it if a is truthy, otherwise it'll evaluate to the list you provided.
There's no need to put the else inside the brackets.
>>> a = 1
>>> [a] if a else [0, 1, 0]
[1]
>>> a = None
>>> [a] if a else [0, 1, 0]
[0, 1, 0]
Related
I am confused on how lists inside lists get sorted.
L = [[1,1,1],[0,9,0],[2,1,1]]
sorted(L) returns [[0, 9, 0], [1, 1, 1], [2, 1, 1]]
This means that it is not based off sum as 0+9+0 is larger than both of the other ones.
No it is based on all the elements of the iterator starting from the first element of the iterator
sorted(L,key=lambda x:(x[0],x[1],x[2]) #==sorted(L)
In case you need by sum
sorted(L,key=sum)
A more simplified version of above code to understand the key argument further
print(sorted(L,key=lambda x: x[0]+x[1]+x[2]))
Built-in sorted considers each element of an iterable in turn. So, for example, [0, 9, 0] appears first because 0 < 1 and 0 < 2.
To help gain intuition, you can test a few examples:
[0,9,0] < [1,1,1] # True
[0,9,0] < [0,8,0] # False
[1,1,1] < [2,1,1] # True
So sorted works consistently with how comparison operators are defined. Sequence objects in Python usually support lexicographic comparison. To sort by the sum of each list, you need to feed a function to the key argument, in this case built-in sum:
res = sorted(L, key=sum)
I have a list.
l1 = [0, 0, 2, 0]
l2 = [0, 0, 0, 0]
I want to print list if list contains non zero element in it.
Output:
If one one list passed, then only list with non zero element will get printed. In example above only l1 will get printed.
[0, 0, 2, 0]
I want to know how efficiently it can be done. Thanks !
Use any on your lists:
for lst in (l1, l2):
if any(lst):
print(lst)
You can also use all:
for lst in (l1, l2):
if all(x != 0 for x in lst):
print(lst)
I hope this helps.
You can use the built-in function any():
From Python's documentation:
any(iterable)
Return True if any element of the iterable is true. If
the iterable is empty, return False
Here's a code:
for l in [l1,l2, ..., ln]:
if any(l):
print(l)
You can try this:
lists = [[0, 0, 0, 0],[0, 0, 2, 0]]
for l in lists:
if set(l)=={0}:
pass
else:
print l
You can use the built-in any to test if the list contains at least one non-Falsy/non-zero element.
Zero is falsy, in fact the only falsy number:
>>> bool(0)
False
So you can easily do:
for lst in (l1, l2):
if any(lst):
print(lst)
This would provide correct results as long as your lists contains only numericals and you're not willing to make an expcetion of non numericals.
Answered in the comments, but I'll post it as an answer:
for l in filter(any, (l1, l2)):
print(l)
The combination of filter and any makes it so the print only executes for lists with non-zero elements. any returns False as soon as the first non-zero (or truthy) value is encountered. For integers, 0 is the only i for which bool(i) is falsey.
I'm trying to figure out how to delete an entire list at a specific index if the first element on the inside list meets a certain condition. Below I've shown an example of what I want done but when I run the code I'm getting a list index out of range error in python. If the list[i][0] meets a certain condition I want that entire list delete from the overall list.
list = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
for i in range(0, len(list)):
if list[i][0] == 0:
del list[i]
return list
Below I've shown a picture of what happens when I run the sample code in IDLE, the first time I run the loop it gives an error but the second time I run the code (copy and pasted both times) it doesn't and it does what I'm asking.
Weird Python Error
Deleting an element from the middle of a list moves everything down, breaking indexing. You need to either remove elements from the end:
for i in range(len(lst)-1, -1, -1):
if lst[i][0] == 0:
del lst[i]
or build a new list and assign it back to the variable, which would also be much more efficient:
lst = [x for x in lst if x[0] != 0]
Try changing your code to this, and 'list' is not a good variable name since it's already a builtin function:
my_list = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
my_list = [l for l in list if l[0] != 0]
print(my_list)
Usually it's not a good idea to remove elements from list while iterating through it like that because the first time you remove an element the list will no longer be the same length.
1) Create completely new list which will contain elements you want to keep:
listname = [element for element in listname if element[0] != 0]
2) Modify the list you already have (you can do this since lists are mutable):
listname[:] = [element for element in listname if element[0] != 0]
I would recommend using the second approach in case you have references to the same list somewhere else in you program.
Also try not to name your variables list, it's really not a good practice and it probably is not possible since it's keyword.
First, do not ever call your variables list.
Second, a while loop may be a slightly better solution:
stop = range(len(mylist))
i = 0
while i < stop:
if mylist[i][0] == 0:
del mylist[i]
stop -= 1
else:
i += 1
Third, a list comprehension is event better:
[item for item in mylist if item[0] != 0]
It's always bad idea to remove elements from a container while you are iterating over it.
A better approach would be to instead of removing bad elements from the list, copy good ones to a new list:
original = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
new_list = []
for l in original:
if list[0] != 0:
new_list.append(l)
return new_list
And by the way, "list" is a python keyword and can't be used as variable name.
Or better, use the built-in filter function:
return filter(lambda l : l[0] != 0, original)
I have this problem on writing a python function which takes a bit list as input and prints the items represented by this bit list.
so the question is on Knapsack and it is a relatively simple and straightforward one as I'm new to the python language too.
so technically the items can be named in a list [1,2,3,4] which corresponds to Type 1, Type 2, Type 3 and etc but we won't be needing the "type". the problem is, i represented the solution in a bit list [0,1,1,1] where 0 means not taken and 1 means taken. in another words, item of type 1 is not taken but the rest are taken, as represented in the bit list i wrote.
now we are required to write a python function which takes the bit list as input and prints the item corresponding to it in which in this case i need the function to print out [2,3,4] leaving out the 1 since it is 0 by bit list. any help on this? it is a 2 mark question but i still couldn't figure it out.
def printItems(l):
for x in range(len(l)):
if x == 0:
return False
elif x == 1:
return l
i tried something like that but it is wrong. much appreciated for any help.
You can do this with the zip function that takes two tiers Lee and returns them in pairs:
for bit_item, item in zip(bit_list, item_list):
if bit_item:
print item
Or if you need a list rather than printing them, you can use a list comprehension:
[item for bit_item, item in zip(bit_list, item_list) if bit_item]
You can use itertools.compress for a quick solution:
>>> import itertools
>>> list(itertools.compress(itertools.count(1), [0, 1, 1, 1]))
[2, 3, 4]
The reason your solution doesn't work is because you are using return in your function, where you need to use print, and make sure you are iterating over your list correctly. In this case, enumerate simplifies things, but there are many similar approaches that would work:
>>> def print_items(l):
... for i,b in enumerate(l,1):
... if b:
... print(i)
...
>>> print_items([0,1,1,1])
2
3
4
>>>
You may do it using list comprehension with enumerate() as:
>>> my_list = [0, 1, 1, 1]
>>> taken_list = [i for i, item in enumerate(my_list, 1) if item]
>>> taken_list # by default start with 0 ^
[2, 3, 4]
Alternatively, in case you do not need any in-built function and want to create your own function, you may modify your code as:
def printItems(l):
new_list = []
for x in range(len(l)):
if l[x] == 1:
new_list.append(x+1) # "x+1" because index starts with `0` and you need position
return new_list
Sample run:
>>> printItems([0, 1, 1, 1])
[2, 3, 4]
I am trying to make this as clear as I can. Please let me know if I should clarify anything.
I have a long list of variables in a list in the following format -
L = ["Fruit", "Transportation", "Housing", "Food", "Education"]
I would like to map a shorter list into it. The shorter list does not have each but only some of the variables in the long list. For instance -
S = ["Fruit", "Food"]
What I am interested in obtaining is the binary values of the short list while it maps into the L list.
With S as an example, it should be:
S = [1, 0, 0, 1, 0]
I tried map(S, L) but clearly a list is not callable.
TypeError: 'list' object is not callable
What would be a good way to do this? Thank you!!
By using a list comprehension that takes every value in L and if it is contained inside S it returns a value of 1, and, if not, it returns a value of 0:
m = [1 if subval in S else 0 for subval in L]
the result is:
[1, 0, 0, 1, 0]
Try this:
[int(x in S) for x in L]
You can use python's list comprehension as follow:
ans=[1 if x in S else 0 for x in L]
I tried map(S, L) but clearly a list is not callable.
But its methods are:
>>> map(S.count, L)
[1, 0, 0, 1, 0]
(This one assumes there are no duplicates in S. If that's not the case, you could for example use map(list(set(S)).count, L) instead.)