How I make multiline list comprehension in Python?
Something like:
[
x for x in a:
if check(x):
....
#something multiline here
....
else:
....
#something multiline here
....
]
Of course I know that I can to something like:
def f(x):
if check(x):
....
else:
....
return x
map(a,f)
But I want it without additional functions.
Is it possible?
My understanding is that you can not do it as you suggested.
It's far more readable when you name the function and use list comprehension or map function compared to what you have suggested
You can't, in the way you're thinking; list comprehensions can only contain expressions, not statements.
You can have multiline list comprehensions and you can have if statements inside them, but the syntax is different from what you showed. I just tested this in the interpreter:
>>> tuple = ('a','b','c','d','e','f','g','h','i','j')
>>> list = [letter for letter in tuple
... if (letter != 'a' and letter != 'b')]
>>> list
['c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
You could also break it in other way, but the code will be a bit more messy:
>>> list = [letter for letter in
... tuple if (letter != 'j' and letter != 'i')]
>>> list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
As the other guys pointed out, you might not use an else statement (couldn't make it work here). Besides, if the list comprehension start to grow too much it lose its conciseness (which I think it's strongest point).
Of course you can do multiple nested list comprehensions. I do it all the time. Here is one example:
A=[[[10 for y in range(3)],2][x<=3] for x in range(7)]
print A
It generates a list with 4 times 2 and three sublists with 3 times 10 as elements.
[2, 2, 2, 2, [10, 10, 10], [10, 10, 10], [10, 10, 10]]
As you can see, the outer list comprehension generates the 6 elements of the outer list, and the inner (first) list comprehension generates the inner 10s or the 2s, depending on whether x is smaller or equal to 3.
Related
I'm learning python and I have been trying to make an automatic list of lists. For example:
The next list, which I have to split to get a list of separated letters, and then join them again to make a two lists of separated letters
lists=[['a,b,c,h'],['d,e,f,g']]
print('list length', len(lists))
splited=[]
splited1=lists[0][0].split(',')
print(splited1) #['a', 'b', 'c', 'h']
splited2=lists[1][0].split(',')
print(splited2) #['d', 'e', 'f', 'g']
listcomb=[splited1,splited2]
print(listcomb) #[['a', 'b', 'c', 'h'], ['d', 'e', 'f', 'g']]
This is what I want to get, a list that have 2 lists, but in the case I have to get more lists inside that list i want to make it automatic with a for loop.
My try, but it didn't work
listcomb2=zip(splited1,splited2)
print(listcomb2)
sepcomb = list()
print(type(sepcomb))
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb[x]=[sep]
print(sepcomb)
I'm having problems with splitting the letters and then joining them in a new list. Pls help
Make some tweak in your code. As we can see lenght of sepcomb is 0 so use append method to avoid this problem. As sepcomb[x]=[sep] is is assignment to x-index but it x index doesn't exist so, it will raise error
change:
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb[x]=[sep]
to
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb.append(sep)
Method-2
sepcomb = list(i[0].split(',') for i in lists)
You can simply do the following:
final=[splinted1]+[splinted2]
Or a better way directly from the lists variable would be:
final=[value[0].split(',') for value in lists]
Here you go:
lists = [['a,b,c,h'],['d,e,f,g']]
listcomb = []
for each in lists:
splited = each[0].split(',')
listcomb.append(splited)
print(listcomb)
list1 = [['apple','b','c'] ,['dolly','e','f']]
list2 =[['awsme','b','c'] ,['dad','e','f'],['tally','e','f']]
list_combine = [item for sublst in zip(list1, list2) for item in sublst]
print(list_combine)
Expected Output:
list_combine = [['apple','b','c'] ,['dolly','e','f'],['awsme','b','c'] ,['dad','e','f'],['tally','e','f']]
How to merge 2 unequal nested list into single nested list in python
You can just use the '+' operator to join 2 lists.
list_combine = list1 + list2
print(list_combine)
Output
list_combine = [['apple','b','c'] ,['dolly','e','f'],['awsme','b','c'] ,['dad','e','f'],['tally','e','f']]
You may simply concatenate the two lists by defining a new variable like list3 or whatever you call.
Also due to PEP8, I just modified your code in a more Pythonic way so that it would be more readable. Things like space before comma in not suggested, but after that is recommended. This recommendation is not just in Python, but also it is the better way to write in English grammatically too.
You may check this out and inform me should you have any doubts and questions regarding my answer:
list1 = [['apple', 'b', 'c'], ['dolly', 'e', 'f']]
list2 = [['awsme', 'b', 'c'], ['dad', 'e', 'f'], ['tally', 'e', 'f']]
list3 = list1 + list2
print(list3)
I hope it would be useful.
I am searching through a list like this:
my_list = [['a','b'],['b','c'],['a','x'],['f','r']]
and I want to see which elements come with 'a'. So first I have to find lists in which 'a' occurs. Then get access to the other element of the list. I do this by abs(pair.index('a')-1)
for pair in my_list:
if 'a' in pair:
print( pair[abs(pair.index('a')-1)] )
Is there any better pythonic way to do that?
Something like: pair.index(not 'a') maybe?
UPDATE:
Maybe it is good to point out that 'a' is not necessarily the first element.
in my case, ['a','a'] doesn't happen, but generally maybe it's good to choose a solution which handles this situation too
Are you looking for elements that accompany a? If so, a simple list comprehension will do:
In [110]: [x for x in my_list if 'a' in x]
Out[110]: [['a', 'b'], ['a', 'x']]
If you just want the elements and not the pairs, how about getting rid of a before printing:
In [112]: [(set(x) - {'a'}).pop() for x in my_list if 'a' in x]
Out[112]: ['b', 'x']
I use a set because a could either be the first or second element in the pair.
If I understand your question correctly, the following should work:
my_list = filter(
lambda e: 'a' not in e,
my_list
)
Note that in python 3, this returns a filter object instance. You may want to wrap the code in a list() command to get a list instance instead.
That technique works ok here, but it may be more efficient, and slightly more readable, to do it using sets. Here's one way to do that.
def paired_with(seq, ch):
chset = set(ch)
return [(set(pair) - chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r']]
print(paired_with(my_list, 'a'))
output
['b', 'x']
If you want to do lots of tests on the same list, it would be more efficient to build a list of sets.
def paired_with(seq, ch):
chset = set(ch)
return [(pair - chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r']]
my_sets = [set(u) for u in my_list]
print(my_sets)
print(paired_with(my_sets, 'a'))
output
[{'b', 'a'}, {'c', 'b'}, {'x', 'a'}, {'r', 'f'}]
['b', 'x']
This will fail if there's a pair like ['a', 'a'], but we can easily fix that:
def paired_with(seq, ch):
chset = set(ch)
return [(pair - chset or chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r'], ['a', 'a']]
my_sets = [set(u) for u in my_list]
print(paired_with(my_sets, 'a'))
output
['b', 'x', 'a']
This question already has answers here:
A quick way to return list without a specific element in Python
(9 answers)
Closed 5 months ago.
Just noticed that there is no function in Python to remove an item in a list by index, to be used while chaining.
For instance, I am looking for something like this:
another_list = list_of_items.remove[item-index]
instead of
del list_of_items[item_index]
Since, remove(item_in_list) returns the list after removing the item_in_list; I wonder why a similar function for index is left out. It seems very obvious and trivial to have been included, feels there is a reason to skip it.
Any thoughts on why such a function is unavailable?
----- EDIT -------
list_of_items.pop(item_at_index) is not suitable as it doesn't return the list without the specific item to remove, hence can't be used to chain. (As per the Docs: L.pop([index]) -> item -- remove and return item at index)
Here's a nice Pythonic way to do it using list comprehensions and enumerate (note that enumerate is zero-indexed):
>>> y = [3,4,5,6]
>>> [x for i, x in enumerate(y) if i != 1] # remove the second element
[3, 5, 6]
The advantage of this approach is that you can do several things at once:
>>> # remove the first and second elements
>>> [x for i, x in enumerate(y) if i != 0 and i != 1]
[5, 6]
>>> # remove the first element and all instances of 6
>>> [x for i, x in enumerate(y) if i != 0 and x != 6]
[4, 5]
Use list.pop:
>>> a = [1,2,3,4]
>>> a.pop(2)
3
>>> a
[1, 2, 4]
According to the documentation:
s.pop([i])
same as x = s[i]; del s[i]; return x
UPDATE
For chaining, you can use following trick. (using temporary sequence that contains the original list):
>>> a = [1,2,3,4]
>>> [a.pop(2), a][1] # Remove the 3rd element of a and 'return' a
[1, 2, 4]
>>> a # Notice that a is changed
[1, 2, 4]
To get the result of removing (i.e, a new list, not in-place) a single item by index, there is no reason to use enumerate or a list comprehension or any other manual, explicit iteration.
Instead, simply slice the list before and after, and put those pieces together. Thus:
def skipping(a_list, index):
return a_list[:index] + a_list[index+1:]
Let's test it:
>>> test = list('example')
>>> skipping(test, 0)
['x', 'a', 'm', 'p', 'l', 'e']
>>> skipping(test, 4)
['e', 'x', 'a', 'm', 'l', 'e']
>>> skipping(test, 6)
['e', 'x', 'a', 'm', 'p', 'l']
>>> skipping(test, 7)
['e', 'x', 'a', 'm', 'p', 'l', 'e']
>>> test
['e', 'x', 'a', 'm', 'p', 'l', 'e']
Notice that it does not complain about an out-of-bounds index, because slicing doesn't in general; this must be detected explicitly if you want an exception to be raised. If we want negative indices to work per Python's usual indexing rules, we also have to handle them specially, or at least -1 (it is left as an exercise to understand why).
Fixing those issues:
def skipping(a_list, index):
count = len(a_list)
if index < 0:
index += count
if not 0 <= index < count:
raise ValueError
return a_list[:index] + a_list[index+1:]
As Martijn Pieters noted in comments to the question, this is not implemented as: Python in-place operations, as a rule, return None, never the altered object.
what I basically need is to check every element of a list and if some criteria fit I want to remove it from the list.
So for example let's say that
list=['a','b','c','d','e']
I basically want to write (in principle and not the actual code I try to implement)
If an element of the list is 'b' or 'c' remove it from the list and take the next.
But
for s in list:
if s=='b' or s=='c':
list.remove(s)
fails because when 'b' is removed the loop takes 'd' and not 'c' as the next element. So is there a way to do that faster than storing the elements in a separate list and removing them afterwards?
Thanks.
The easier way is to use a copy of the list - it can be done with a slice that extends "from the beginning" to the "end" of the list, like this:
for s in list[:]:
if s=='b' or s=='c':
list.remove(s)
You have considered this, and this is simple enough to be in your code, unless this list is really big, and in a critical part of the code (like, in the main loop of an action game). In that case, I sometimes use the following idiom:
to_remove = []
for index, s in enumerate(list):
if s == "b" or s == "c":
to_remove.append(index)
for index in reversed(to_remove):
del list[index]
Of course you can resort to a while loop instead:
index = 0
while index < len(list):
if s == "b" or s == "c":
del list[index]
continue
index += 1
Its better not to reinvent things which are already available. Use filter functions and lambda in these cases. Its more pythonic and looks cleaner.
filter(lambda x:x not in ['b','c'],['a','b','c','d','e'])
alternatively you can use list comprehension
[x for x in ['a','b','c','d','e'] if x not in ['b','c']]
This is exactly what itertools.ifilter is designed for.
from itertools import ifilter
ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])
will give you back a generator for your list. If you actually need a list, you can create it using one of the standard techniques for converting a generator to a list:
list(ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e']))
or
[x for x in ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])]
If you are ok with creating a copy of the list you can do it like this (list comprehension):
[s for s in list if s != 'b' and s != 'c']