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
Related
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
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
I need to slice a list of lists:
A = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
idx = slice(0,4)
B = A[:][idx]
The code above isn't giving me the right output.
What I want is: [[1,2,3],[1,2,3],[1,2,3]]
Very rarely using slice objects is easier to read than employing a list comprehension, and this is not one of those cases.
>>> A = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
>>> [sublist[:3] for sublist in A]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
This is very clear. For every sublist in A, give me the list of the first three elements.
With numpy it is very simple - you could just perform the slice:
In [1]: import numpy as np
In [2]: A = np.array([[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]])
In [3]: A[:,:3]
Out[3]:
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
You could, of course, transform numpy.array back to the list:
In [4]: A[:,:3].tolist()
Out[4]: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
A = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
print [a[:3] for a in A]
Using list comprehension
you can use a list comprehension such as: [x[0:i] for x in A]
where i is 1,2,3 etc based on how many elements you need.
Either:
>>> [a[slice(0,3)] for a in A]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
Or:
>>> [list(filter(lambda x: x<=3, a)) for a in A]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
I am new in programming and Python is my First Language. it's only 4 to 5 days only to start learning. I just learned about List and slicing and looking for some example I found your problem and try to solve it Kindly appreciate if my code is correct.
Here is my code
A = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
print(A[0][0:3],A[1][0:3],A[1][0:3])
Suppose that I have a list x=[1, 2, 3, 4], it contains the sublists [1], [2], [3], [4], [1, 2], [2, 3], [3, 4], [1,2,3], [2,3,4] and [1,2,3,4]. But it does not contain something like [1, 3] because there is a gap as 2 appears between 1 and 3 in x.
Does anybody know what the best way is to test if a list is contained within another list without gap? I have thought about a for-loop solution, but it might not be a very good solution. Thanks.
Your question is:
Does anybody know what the best way is to test if a list is contained
within another list without gap?
That's actually identical to the problem of finding a string in another string. And for that you have plenty of algorithms available.
Rabin–Karp, Boyer–Moore, Knuth–Morris, etc. I like the Boyer-Moore because of its simplicity. Have a look on the details on the Internet. Of course you could also check if you list is starting from any possible position, but the complexity is not optimal (you can find such solutions here: Check for presence of a sliced list in Python).
Here's a quick (and simplified) implementation for you:
def boyer(x, sublist):
p = len(sublist) - 1
i = 0
while i + p < len(x):
if x[i + p] == sublist[p]:
if p == 0:
return True
p -= 1
elif x[i + p] in sublist:
i += 1
p = len(sublist) - 1
else:
i = i + p + 1
p = len(sublist) - 1
return False
Note that this code should be tested carefully and is more about showing an alternative to the brute force approach. The time complexity of x[i + p] in sublist is linear and should be implemented differently to get a O(1) method. Currently, because of that, it won't be better than the brute force approach.
You can try
' '.join(str(c) for c in list1) in ' '.join(str(c) for c in list2)
sequences = [
[1], [2],
[1, 2], [2, 3], [3, 6],
[1, 2, 3], [2, 3, 4], [1, 2, 3, 5],
]
bad_seq = lambda s: s and s != list(range(s[0], s[0] + len(s)))
print filter(bad_seq, sequences) # [[3, 6], [1, 2, 3, 5]]
Just another solution, not sure the best of its kind, please let me know if i don't understand your question clearly.
ls = [[1], [2], [3], [4], [1, 2], [2, 3], [3, 6], [1, 2, 3], [2, 3, 4], [1, 2, 3, 5]]
def gap(l):
for ls in l:
result = list(set(map(lambda x: x[1] - x[0], zip(ls[0:], ls[1:]) )))
if result and (len(result) > 1 or result[0] > 1):
print ls
gap(ls)
Output:
[3,6]
[1, 2, 3, 5]
You can use numpy-diff function on indices of the sublist in the main list
In [427]: x=[1, 2, 3, 4]
In [428]: y = [1,3]
In [429]: z = [1,2,3]
In [430]: w = [2,1]
In [431]: import numpy as np
In [432]: sub_indices = [x.index(x1) for x1 in y]
Now, sub_indices should look like: [0, 2]
So you can check the diff between the indices:
In [433]: np.all(np.diff(sub_indices) == 1)
Out[433]: False
In [434]: sub_indices = [x.index(x1) for x1 in z]
In [435]: np.all(np.diff(sub_indices) == 1)
Out[435]: True
In [436]: sub_indices = [x.index(x1) for x1 in w]
In [437]: np.all(np.diff(sub_indices) == 1)
Out[437]: False
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)