I have such code:
a = [[1, 1], [2, 1], [3, 0]]
I want to get two lists, the first contains elements of 'a', where a[][1] = 1, and the second - elements where a[][1] = 0. So
first_list = [[1, 1], [2, 1]]
second_list = [[3, 0]].
I can do such thing with two list comprehension:
first_list = [i for i in a if i[1] == 1]
second_list = [i for i in a if i[1] == 0]
But maybe exists other (more pythonic, or shorter) way to do this? Thanks for your answers.
List comprehension are very pythonic and the recommended way of doing this. Your code is fine.
If you want to have it in a single line you could do something like
first_list, second_list = [i for i in a if i[1] == 1], [i for i in a if i[1] == 0]
Remember that, "Explicit is better than implicit."
Your code is fine
You can use sorted() and itertools.groupby() to do this, but I don't know that it would qualify as Pythonic per se:
>>> dict((k, list(v)) for (k, v) in itertools.groupby(sorted(a, key=operator.itemgetter(1)), operator.itemgetter(1)))
{0: [[3, 0]], 1: [[1, 1], [2, 1]]}
what about this,
In [1]: a = [[1, 1], [2, 1], [3, 0]]
In [2]: first_list = []
In [3]: second_list = []
In [4]: [first_list.append(i) if i[1] == 1 else second_list.append(i) for i in a]
Out[4]: [None, None, None]
In [5]: first_list, second_list
Out[5]: ([[1, 1], [2, 1]], [[3, 0]])
instead of two sublist, I prefer dict (or defaultdict, OrderedDict, Counter, etc.)
In [6]: from collections import defaultdict
In [7]: d = defaultdict(list)
In [8]: [d[i[1]].append(i) for i in a]
Out[8]: [None, None, None]
In [9]: d
Out[9]: {0: [[3, 0]], 1: [[1, 1], [2, 1]]}
If the lists are reasonably short then two list comprehensions will do fine: you shouldn't be worried about performance until your code is all working and you know it is too slow.
If your lists are long or the code runs often and you have demonstrated that it is a bottleneck then all you have to do is switch from list comprehensions to a for loop:
first_list, second_list = [], []
for element in a:
if element[1] == 1:
first_list.append(element)
else:
second_list.append(element)
which is both clear and easily extended to more cases.
list comprehensions are great. If you want slightly more simple code (but slightly longer) then just use a for loop.
Yet another option would be filters and maps:
a = [[1, 1], [2, 1], [3, 0]]
g1=filter(lambda i: i[1]==1,a)
g1=map(lambda i: i[0],g1)
g2=filter(lambda i: i[1]==0,a)
g2=map(lambda i: i[0],g2)
print g1
print g2
Related
I have a few lists called find. I want to know if these find are part of full_list. Lists find 1-4 are part of full_list while lists find 5-7 are not.
The example below returns "Yes".
find1 = [[1, 1]]
find2 = [[1, 1], [2, 2]]
find3 = [[1, 1], [3, 3]]
find4 = [[4, 4], [2, 2], [3, 3]]
find5 = [[1, 0]]
find6 = [[1, 1], [2, 0]]
find7 = [[1, 1], [3, 0]]
full_list = [[1, 1], [2, 2], [3, 3], [4, 4]]
if find2[0] in full_list and find2[1] in full_list:
print("Yes")
else:
print("No")
Because len(find2) != len(find4), the current if statement is very clumsy and almost useless.
How to make this work in a more universal way?
You could use all() with a generator which returns a True if everything is a truthy or False:
if all(x in full_list for x in find2):
print("Yes")
else:
print("No")
# => prints Yes
This one is generic, just need to change find2 to any list you need to check with full_list.
Try this:
set1 = set(find1)
full_set = set(full_list)
if set1.issubset(full_set):
print("Yes")
else:
print("No")
You could set up a function to process all of these, all the mentioned methods will work, just displaying other options, you could use filter and compare the lens as well
def is_in_full(k):
l = list(filter(lambda x: x in k, full_list))
if len(l) == len(k):
return 'Yes'
else:
return 'No'
print(is_in_full(find1))
# Yes
assume i have
a=[[0,1],[2,1],[0,2],[1,3]]
i would like to have a result like this
b=[[0,1],[0,2],[1,2],[1,3]]
The tricky part is to sort the [2,1] to [1,2] and sort the whole list again. I tried
sorted(a, key=lambda x: (x[0]))
but it give me [[0,1],[0,2],[1,3],[2,1]]
Any suggestion?
Try to sort the sublist first:
print sorted([sorted(i) for i in a])
Update It could be done slightly better, passing a list comprehension to sorted() results in a copy of the list being made, so you can just remove it:
print sorted(sorted(i) for i in a)
Result
[[0, 1], [0, 2], [1, 2], [1, 3]]
As #PM2Ring said, using the lambda maybe return the wrong result, it should be removed.
Can you try the below using comprehension.
>>> b=sorted([sorted(s) for s in a])
>>> b
[[0, 1], [0, 2], [1, 2], [1, 3]]
It should work.
try this:
b=sorted([sorted(small_list) for small_list in a ])
Try this:
>>> [sorted(i) for i in sorted(a, key=lambda x: (min(x), sum(x)))]
[[0, 1], [0, 2], [1, 2], [1, 3]]
I got a list as follows:
list_1 = [[3, 0], [0, 3], [3, 4]]
I'm trying to filter out the commutative elements in this. For example, [3,0] and [0,3] are the same and I need to keep only one of them. I tried converting this into a set, and it didn't help. I also tried iterating, but it's causing real overhead. Is there any Pythonic way to do this?
Thanks.
For example, you can use dict comprehension:
>>> {tuple(sorted(t)): t for t in list_1}.values()
[[0, 3], [3, 4]]
You can use a set of frozensets for the filtering.
If order does not matter:
>>> map(list, set(frozenset(t) for t in list_1))
[[3, 4], [0, 3]]
To retain order:
list_1 = [[3, 0], [0, 3], [3, 4]]
seen = set()
filtered = []
for item in list_1:
item_set = frozenset(item)
if item_set not in seen:
filtered.append(item)
seen.add(item_set)
Result:
>>> filtered
[[3, 0], [3, 4]]
I have a list of lists like this
list = [[1, 2], [1, 3], [4, 5]]
and as you see the first element of the first two sublists is repeated
So I want my output too be:
list = [[1, 2, 3], [4, 5]]
Thank you
The following code should solve your problem:
def merge_subs(lst_of_lsts):
res = []
for row in lst_of_lsts:
for i, resrow in enumerate(res):
if row[0]==resrow[0]:
res[i] += row[1:]
break
else:
res.append(row)
return res
Note that the elsebelongs to the inner for and is executed if the loop is exited without hitting the break.
I have a solution that builds a dict first with the 1st values, then creates a list from that, but the order may not be the same (i.e. [4, 5] may be before [1, 2, 3]):
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> map(lambda x: d[x[0]].append(x[1]), l)
[None, None, None]
>>> d
defaultdict(<type 'list'>, {1: [2, 3], 4: [5]})
>>> [[key] + list(val) for key, val in d.iteritems()]
[[1, 2, 3], [4, 5]]
You can use python sets, because you can compute intersection and union pretty easy. The code would be more clear, but the complexity would probably be comparable to the other solutions.
Although arguably unreadable:
# Note the _ after the list, otherwise you are redefining the list type in your scope
list_ = [[1, 2], [1, 3], [4, 5]]
from itertools import groupby
grouper = lambda l: [[k] + sum((v[1::] for v in vs), []) for k, vs in groupby(l, lambda x: x[0])]
print grouper(list_)
A more readable variant:
from collections import defaultdict
groups = defaultdict(list)
for vs in list_:
group[vs[0]] += vs[1:]
print group.items()
Note that these solve a more generic form of your problem, instead of [[1, 2], [1, 3], [4, 5]] you could also have something like this: [[1, 2, 3], [1, 4, 5], [2, 4, 5, 6], [3]]
Explanation about the _. This is why you don't want to overwrite list:
spam = list()
print spam
# returns []
list = spam
print list
# returns []
spam = list()
# TypeError: 'list' object is not callable
As you can see above, by setting list = spam we broke the default behaviour of list().
I have a list of lists, say:
arr = [[1, 2], [1, 3], [1, 4]]
I would like to append 100 to each of the inner lists. Output for the above example would be:
arr = [[1, 2, 100], [1, 3, 100], [1, 4, 100]]
I can of course do:
for elem in arr:
elem.append(100)
But is there something more pythonic that can be done? Why does the following not work:
arr = [elem.append(100) for elem in arr]
The second version should be written like arr = [elem + [100] for elem in arr]. But the most pythonic way if you ask me is the first one. The for construct has it's own use, and it suits very well here.
Note that your code also works - the only thing you have to know is that there is no need to assign result to variable in such a case:
arr = [[1, 2], [1, 3], [1, 4]]
[x.append(100) for x in arr]
After execution arr will contain updated list [[1, 2, 100], [1, 3, 100], [1, 4, 100]], e.g it work like in-place update, but this not very common practice to do this.
The same result you will get in the next case:
map(lambda x: x.append(100), arr)
As was discussed you can use list comprehension or map to do this with assigning result to any variable:
res = map(lambda x: x + [100], arr)
You can do
[a + [100] for a in arr]
The reason why your append doesn't work is that append doesn't return the list, but rather None.
Of course, this is more resource intensive than just doing append - you end up making copies of everything.
This is the more pythonic way
for elem in arr:
elem.append(100)
but as an option you can also try this:
[arr[i].append(100) for i in range(len(arr))]
print arr # It will return [[1, 2, 100], [1, 3, 100], [1, 4, 100]]