I have a problem:
list = [1,2,3,4,5]
a= 3
if a==[item for item in list]:
print(sth)
why the program never print?
thanks...
You're comparing an integer to a list, which will never return True as they are different types. Note that [item for item in list] is exactly the same as just saying list.
You're probably wondering if 3 is in the list; so you can do:
if a in list:
print(sth)
Or even:
if any(a == item for item in list):
print(sth)
(Although you really should just use the first option. I only put the second option in as it looks similar to your example :p)
As a side note, you shouldn't be naming lists list, or dictionaries dict, as they are built-in types already, and you're just overriding them :p.
Related
I have a list, which potentially contains a list (and this subsequently can also can be made up of lists, ad infinitum). Is there a way to test if any element at the 'bottom' of these lists has an integer? The list will always have numbers (floats or ints) eventually.
As I don't know the number of nested lists of it beforehand, the only way I can think of doing so would be something like,
x = [[[[5]]]]
if (len(str(x)) != len(str(x).replace('.','')) or ('int' not in str(x)):
int_in_list = False
Is there a more logical way of doing this?
I'd recommend using something like collapse() from the more-itertools library, which will recursively descend into lists and other iterable types and yield the fundamental non-iterable elements. You can then just check whether any of the elements yielded by collapse() is an integer.
any(isinstance(x, int) for x in collapse(...))
Here ya go:
numlist = [[[[[1]]]]]
def recursive_flatten(lst):
for item in lst:
if isinstance(item, list):
yield from recursive_flatten(item)
yield item
if any(isinstance(item, int) for item in recursive_flatten(numlist)):
# Horray
pass
New to Python here. I've figured out that it's rather trivial to check if a list has all unique elements using
if len(lst) > len(set(lst))
But how would I deal with a case like this?
all_different([[],[],[],[]]) #False
I can't use the set() function in this example. I understand how I might do this (rather inefficiently) with nested for loops in Java. But not sure how I could implement this in Python.
You can't hash lists as they're mutable, but you can convert them to tuples, and hash them instead. Like so: set(tuple(elem) for elem in lst)
Your comparison would then become:
myset = set(tuple(elem) for elem in lst)
if len(lst) > len(myset)
I want to look for a certain item in a list, but there may be more than 1 of this item in the list, but I want it so that for each item in the list, it will do something.
For example:
list = ["1", "1", "2"]
for "1" in list:
print ("hi")
and it should print out 'hi' twice, for the 2 '1's in the list.
You can use the count method to do this:
lst = ["1", "1", "2"]
for i in range(lst.count("1")):
print "Hi"
One liner:
print "Hi\n" * lst.count("1")
Note: I have changed the variable name 'list' to 'lst' as a good practice to avoid the python's keyword overriding.
You can do this easily with python's built in filter syntax:
def hi(number, lst):
for item in (element for element in lst if element == number):
print('hi')
The advantage of this method over the others presented is that you can actually do something with the elements that match your criteria as you iterate, should you wish to.
Usage:
>>>hi(1,[1,1,2])
hi
hi
I think this is the simplest, most readable syntax. It says exactly what it does, imports no modules, calls no functions and creates no temporary variables. It would be easy to substitute any comparison and any function taking item as a parameter.
for item in lst:
if element == number:
print('hi')
I've got a list in which some items shall be moved into a separate list (by a comparator function). Those elements are pure dicts. The question is how should I iterate over such list.
When iterating the simplest way, for element in mylist, then I don't know the index of the element. There's no .iteritems() methods for lists, which could be useful here. So I've tried to use for index in range(len(mylist)):, which [1] seems over-complicated as for python and [2] does not satisfy me, since range(len()) is calculated once in the beginning and if I remove an element from the list during iteration, I'll get IndexError: list index out of range.
Finally, my question is - how should I iterate over a python list, to be able to remove elements from the list (using a comparator function and put them in another list)?
You can use enumerate function and make a temporary copy of the list:
for i, value in enumerate(old_list[:]):
# i == index
# value == dictionary
# you can safely remove from old_list because we are iterating over copy
Creating a new list really isn't much of a problem compared to removing items from the old one. Similarly, iterating twice is a very minor performance hit, probably swamped by other factors. Unless you have a very good reason to do otherwise, backed by profiling your code, I'd recommend iterating twice and building two new lists:
from itertools import ifilter, ifilterfalse
l1 = list(ifilter(condition, l))
l2 = list(ifilterfalse(condition, l))
You can slice-assign the contents of one of the new lists into the original if you want:
l[:] = l1
If you're absolutely sure you want a 1-pass solution, and you're absolutely sure you want to modify the original list in place instead of creating a copy, the following avoids quadratic performance hits from popping from the middle of a list:
j = 0
l2 = []
for i in range(len(l)):
if condition(l[i]):
l[j] = l[i]
j += 1
else:
l2.append(l[i])
del l[j:]
We move each element of the list directly to its final position without wasting time shifting elements that don't really need to be shifted. We could use for item in l if we wanted, and it'd probably be a bit faster, but when the algorithm involves modifying the thing we're iterating over, I prefer the explicit index.
I prefer not to touch the original list and do as #Martol1ni, but one way to do it in place and not be affected by the removal of elements would be to iterate backwards:
for i in reversed(range(len()):
# do the filtering...
That will affect only the indices of elements that you have tested/removed already
Try the filter command, and you can override the original list with it too if you don't need it.
def cmp(i): #Comparator function returning a boolean for a given item
...
# mylist is the initial list
mylist = filter(cmp, mylist)
mylist is now a generator of suitable items. You can use list(mylist) if you need to use it more than once.
Haven't tried this yet but.. i'll give it a quick shot:
new_list = [old.pop(i) for i, x in reversed(list(enumerate(old))) if comparator(x)]
You can do this, might be one line too much though.
new_list1 = [x for x in old_list if your_comparator(x)]
new_list2 = [x for x in old_list if x not in new_list1]
A multidimensional list like l=[[1,2],[3,4]] could be converted to a 1D one by doing sum(l,[]). How does this happen?
(This doesn't work directly for higher multidimensional lists, but it can be repeated to handle those cases. For example if A is a 3D-list, then sum(sum(A),[]),[]) will flatten A to a 1D list.)
If your list nested is, as you say, "2D" (meaning that you only want to go one level down, and all 1-level-down items of nested are lists), a simple list comprehension:
flat = [x for sublist in nested for x in sublist]
is the approach I'd recommend -- much more efficient than summing would be (sum is intended for numbers -- it was just too much of a bother to somehow make it block all attempts to "sum" non-numbers... I was the original proposer and first implementer of sum in the Python standard library, so I guess I should know;-).
If you want to go down "as deep as it takes" (for deeply nested lists), recursion is the simplest way, although by eliminating the recursion you can get higher performance (at the price of higher complication).
This recipe suggests a recursive solution, a recursion elimination, and other approaches
(all instructive, though none as simple as the one-liner I suggested earlier in this answer).
sum adds a sequence together using the + operator. e.g sum([1,2,3]) == 6. The 2nd parameter is an optional start value which defaults to 0. e.g. sum([1,2,3], 10) == 16.
In your example it does [] + [1,2] + [3,4] where + on 2 lists concatenates them together. Therefore the result is [1,2,3,4]
The empty list is required as the 2nd paramter to sum because, as mentioned above, the default is for sum to add to 0 (i.e. 0 + [1,2] + [3,4]) which would result in unsupported operand type(s) for +: 'int' and 'list'
This is the relevant section of the help for sum:
sum(sequence[, start]) -> value
Returns the sum of a sequence of
numbers (NOT strings) plus the value
of parameter 'start' (which defaults
to 0).
Note
As wallacoloo comented this is not a general solution for flattening any multi dimensional list. It just works for a list of 1D lists due to the behavior described above.
Update
For a way to flatten 1 level of nesting see this recipe from the itertools page:
def flatten(listOfLists):
"Flatten one level of nesting"
return chain.from_iterable(listOfLists)
To flatten more deeply nested lists (including irregularly nested lists) see the accepted answer to this question (there are also some other questions linked to from that question itself.)
Note that the recipe returns an itertools.chain object (which is iterable) and the other question's answer returns a generator object so you need to wrap either of these in a call to list if you want the full list rather than iterating over it. e.g. list(flatten(my_list_of_lists)).
For any kind of multidiamentional array, this code will do flattening to one dimension :
def flatten(l):
try:
return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]
except IndexError:
return []
It looks to me more like you're looking for a final answer of:
[3, 7]
For that you're best off with a list comprehension
>>> l=[[1,2],[3,4]]
>>> [x+y for x,y in l]
[3, 7]
I wrote a program to do multi-dimensional flattening using recursion. If anyone has comments on making the program better, you can always see me smiling:
def flatten(l):
lf=[]
li=[]
ll=[]
p=0
for i in l:
if type(i).__name__=='list':
li.append(i)
else:
lf.append(i)
ll=[x for i in li for x in i]
lf.extend(ll)
for i in lf:
if type(i).__name__ =='list':
#not completely flattened
flatten(lf)
else:
p=p+1
continue
if p==len(lf):
print(lf)
I've written this function:
def make_array_single_dimension(l):
l2 = []
for x in l:
if type(x).__name__ == "list":
l2 += make_array_single_dimension(x)
else:
l2.append(x)
return l2
It works as well!
The + operator concatenates lists and the starting value is [] an empty list.