Compare/find a list in another list's nested lists - python

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

Related

How to merge smaller sub-elements into larger parent-elements in a list?

I have a list of lists, but some lists are "sublists" of other lists. What I want to do is remove the sublists from the larger list so that we only have the largest unique sublists.
For example:
>>> some_list = [[1], [1, 2], [1, 2, 3], [1, 4]]
>>> ideal_list = [[1, 2, 3], [1, 4]]
The code that I've written right now is:
new_list = []
for i in range(some_list)):
for j in range(i + 1, len(some_list)):
count = 0
for k in some_list[i]:
if k in some_list[j]:
count += 1
if count == len(some_list[i]):
new_list.append(some_list[j])
The basic algorithm that I had in mind is that we'd check if a list's elements were in the following sublists, and if so then we use the other larger sublist. It doesn't give the desired output (it actually gives [[1, 2], [1, 2, 3], [1, 4], [1, 2, 3]]) and I'm wondering what I could do to achieve what I want.
I don't want to use sets because duplicate elements matter.
Same idea as set, but using Counter instead. It should be a lot more efficient in sublist check part than brute force
from collections import Counter
new_list = []
counters = []
for arr in sorted(some_list, key=len, reverse=True):
arr_counter = Counter(arr)
if any((c & arr_counter) == arr_counter for c in counters):
continue # it is a sublist of something else
new_list.append(arr)
counters.append(arr_counter)
With some inspiration from #mkrieger1's comment, one possible solution would be:
def merge_sublists(some_list):
new_list = []
for i in range(len(some_list)):
true_or_false = []
for j in range(len(some_list)):
if some_list[j] == some_list[i]:
continue
true_or_false.append(all([x in some_list[j] for x in some_list[i]]))
if not any(true_or_false):
new_list.append(some_list[i])
return new_list
As is stated in the comment, a brute-force solution would be to loop through each element and check if it's a sublist of any other sublist. If it's not, then append it to the new list.
Test cases:
>>> merge_sublists([[1], [1, 2], [1, 2, 3], [1, 4]])
[[1, 2, 3], [1, 4]]
>>> merge_sublists([[1, 2, 3], [4, 5], [3, 4]])
[[1, 2, 3], [4, 5], [3, 4]]
Input:
l = [[1], [1, 2], [1, 2, 3], [1, 4]]
One way here:
l1 = l.copy()
for i in l:
for j in l:
if set(i).issubset(set(j)) and i!=j:
l1.remove(i)
break
This prints:
print(l1)
[[1, 2, 3], [1, 4]]
EDIT: (Taking care of duplicates as well)
l1 = [list(tupl) for tupl in {tuple(item) for item in l }]
l2 = l1.copy()
for i in l1:
for j in l1:
if set(i).issubset(set(j)) and i!=j:
l2.remove(i)
break

Python: Test for equality of certain index in nested lists

I have the following nested list:
nlist = [[2, 0, 4], [2, 0, 4], [0, 0, 4], [0, 0, 4]]
I would like to evaluate whether the first element of each list is equal. I have found methods to evaluate whether the entire nested lists are equal, but not specific indexes?
You could make a set of the first elements of each sub list, and since there is no repetition in sets, you can see if the length of the set is one:
nlist = [[2, 0, 4], [2, 0, 4], [0, 0, 4], [0, 0, 4]]
result = len(set(l[0] for l in nlist)) == 1
print(result) # => False
I would use the all() function with a generator expression as its parameter.
all(sublist[0] == nlist[0][0] for sublist in nlist)
In short, all() will return True if every sublist[0] == nlist[0][0] for every sublist in the original list. It will return False if any item is not equal to nlist[0][0].
you can find all the unique first element and then check index :
>>> from itertools import groupby
>>> nlist = [[2, 0, 4], [2, 0, 4], [0, 0, 4], [0, 0, 4]]
>>> c= [i for i,k in groupby([n[0] for n in nlist])]
>>> c
[2, 0]
>>> d=[[i for i, x in enumerate(nlist) if x[0]==j] for j in c]
>>> d
[[0, 1], [2, 3]]
>>> R=dict(zip(c, d))
>>> R
{0: [2, 3], 2: [0, 1]}
you get a dict with each first possible value and a list of index from your initial list.
first_num = nlist[0][0]
for sublist in nlist:
if first_num != sublist[0]
print(False)
print(True)

Compare 1st element of list from nest list in python

I have a list of lists like following :
[[a1,a2], [b1,b2],...., [n1]]
and I want to find whether the first elements of all these lists are equal?
I'd prefer to do this with a list comprehension unless there's a reason to avoid it, for readability's sake.
list_of_lists = [[1, 2], [1, 3], [1, 4]]
len(set([sublist[0] for sublist in list_of_lists])) == 1
# True
The solution is quite straight forward.
Transpose your list. Use zip to perform this task
Index the first row of your transposed list
Use set to remove duplicate
Determine if no of elements is equal to 1
>>> test = [[1, 2], [1, 3], [1, 4]]
>>> len(set(zip(*test)[0])) == 1
True
Note
If you are using Py 3.X, instead of slicing, wrap the call to zip with next
>>> len(set(next(zip(*test)))) == 1
How about?
>>> from operator import itemgetter
>>> test = [[1, 2], [1, 3], [1, 4]]
>>> len(set(map(itemgetter(0), test))) == 1
True
>>> test.append([2, 5])
>>> test
[[1, 2], [1, 3], [1, 4], [2, 5]]
>>> len(set(map(itemgetter(0), test))) == 1
False
And another way would be (Thanks, Peter DeGlopper!)
all(sublist[0] == test[0][0] for sublist in test)
This version would short-circuit too, so it wouldn't need to check every element in every case.
You can create a list of first elements compared to the first sublist's first element:
False not in [len(yourList[0])>0 and len(x)>0 and x[0] == yourList[0][0] for x in yourList]
With a one liner:
>>> sample = [[1, 2], [1, 3], [1, 4]]
>>> reduce(lambda x, y: x if x == y[0] else None, sample, sample[0][0])
1
>>> sample = [[0, 2], [1, 3], [1, 4]]
>>> reduce(lambda x, y: x if x == y[0] else None, sample, sample[0][0])
None
Try this...
>>> test = [[1, 2], [1, 3], [1, 4]]
>>> eval("==".join(map(lambda x: str(x[0]), test)))
True

Check if a value in a list is equal to some number

I've got a list of data:
[[0, 3], [1, 2], [2, 1], [3, 0]]
And I'm trying to check if any of the individual numers is equal to 3, and if so return which element, so list[0],list[3] e.t.c within the original list contains this value 3.
I've gotten as far as:
for i in range(0, len(gcounter_selection)):
for x in range(0,len(gcounter_selection)):
if any(x) in gcounter_selection[i][x]==3:
print(i)
My list is called gcounter_selection by the way.
But I'm getting a type error:
TypeError: argument of type 'int' is not iterable
I've tried using a generator expression but I couldnt get that to work either.
If I understood correctly, you're looking for list comprehensions:
value = 3
lst = [[0, 3], [1, 2], [2, 1], [3, 0]]
items = [x for x in lst if value in x]
print(items)
#[[0, 3], [3, 0]]
To get elements' positions instead of just elements, add enumerate:
indexes = [n for n, x in enumerate(lst) if value in x]
Fixed version of your original
gcounter_selection = [[0, 3], [1, 2], [2, 1], [3, 0]]
for i in range(0, len(gcounter_selection)):
if any(x == 3 for x in gcounter_selection[i]):
print(i)
However this can be simplified to
for i, x in enumerate(gcounter_selection):
if any(y == 3 for y in x):
print(i)
And there is no need for any in this case, just check with in
for i, x in enumerate(gcounter_selection):
if 3 in x:
print(i)

Python, working with list comprehensions

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

Categories

Resources