I have 2 lists: a = ['5', '2', '3', '4'], and b = ['1', '6', '7', '5']. Using Python 2, how can I compare each list element in a to each element in b? (i.e. is a[0] == b[0], is a[0] == b[1], etc).
I know that I could just write out numerous if statements, but I hope that there is a more elegant way to do this.
After checking each list element, I want to know how many times a shared value was found (in my example lists above, it would be one time, '5').
EDIT: This is not a duplicate, b/c i am comparing two different lists to each other, while the possible duplicate dealt with only 1 list.
The count() method of list may help:
>>> a = ['5', '2', '3', '4']
>>> b = ['1', '6', '7', '5']
>>> for item in a:
... print item, b.count(item)
...
5 1
2 0
3 0
4 0
Probably faster for big inputs than eugene y's, as it only needs to iterate over b once,
instead of len(a) times:
from collections import Counter
counts = Counter(b)
for i in a:
print(i, counts[i])
If you are only concerned with shared values, and not with their positions or counts, convert them to set and use intersection:
>>> a = ['5','2','3','4']
>>> b = ['1','6','7','5']
>>> set(a).intersection(b)
{'5'}
If you want to retain how often the elements appear in the intersection, you can also do an intersection of collections.Counter using &
>>> a = ['5','2','3','4','1','1','6','5']
>>> b = ['1','6','7','5','5']
>>> collections.Counter(a) & collections.Counter(b)
Counter({'5': 2, '1': 1, '6': 1})
Note: This is different from the solution by #GingerPlusPlus in that it is symmetric, i.e. if 5 is present once in list a and twice in list b, then the shared count will be 1, not 2.
def cmp(*lists):
lists_len_min = list(map(lambda x: len(x), lists))
if min(lists_len_min) != max(lists_len_min):
raise Exception("Lists must have equal length")
iterator = iter(lists)
last = next(iterator)
for element in iterator:
for i, each in enumerate(element):
#print(i, last[i], each)
if last[i] != each:
return False
else:
return True
This function can compare as many lists you want with equal length. Just call cmp(list1, list2, list3)
This code will produce list of elements which is consist in both a and b list
a = [1,2,3,4]
b = [2,3,1,7]
c = [e for e in a if e in b]
It might be complex by memory in case if you use big arrays but if you plan to use this data than why not
Related
I have a list like this:
a = [['1','2','3','a','b'],
['4','5','6','c','d'],
['7','8','9','e','f']]
I want to identify the index of an element in the list a based on first three sub-elements of the element. For example, the index of the element which contains ['4','5','6'] as its first three sub-elements is 1.
I have tried to do this using list comprehension follows:
ind = [i for i in range(0,len(a)) if (a[i][0] == '4' and a[i][1] == '5' and a[i][2] == '6')]
But this is computationally expensive as I have to implement this code several times in a for loop. So, I am looking for a less computationally expensive method. SO far I have tried 'list.index' as follows:
ind = a.index(['4','5','6','*','*'])
where '*' is used as wildcard string. But is does not work as it outputs:
['4', '5', '6', '.*', '.*'] is not in list
I think there is something wrong with the way I am using wildcard. Can you please tell me what is it? Or is there another fast way to identify the element of a list based on its sub-elements?
Solution 1: True wildcard
You can simply use a.index(...) if you use a true wildcard:
class Wildcard:
def __eq__(self, anything):
return True
a = [['1','2','3','a','b'],
['4','5','6','c','d'],
['7','8','9','e','f']]
wc = Wildcard()
print(a.index(['4', '5', '6', wc, wc]))
Outputs 1. Try it online!
This might be fast because 1) it does the searching in C code and 2) it does minimal work, as it for example doesn't create a list slice for every row and might often rule out a row simply by looking at just the first value.
Solution 2: operator.indexOf
Or using operator.indexOf, which finds the index in C rather than in Python like an enumerate solution would. Here are two versions of that, I suspect the one mapping a ready-to-go slice is faster:
from operator import indexOf, itemgetter
a = [['1','2','3','a','b'],
['4','5','6','c','d'],
['7','8','9','e','f']]
print(indexOf((r[:3] for r in a), ['4', '5', '6']))
print(indexOf(map(itemgetter(slice(3)), a), ['4', '5', '6']))
Try it online!
Well you could transpose and slice and transpose back and finally index, like this:
>>> list(zip(*list(zip(*a))[:3])).index(('4', '5', '6'))
1
>>>
But what's wrong with?
>>> [x[:3] for x in a].index(['4', '5', '6'])
1
>>>
It may be more efficient to implement it as a generator. In this way, if e.g. you know that you can get at most one match you can stop once it is found:
a = [['1','2','3','a','b'],
['4','5','6','c','d'],
['7','8','9','e','f']]
pattern = ['4','5','6']
def find_index(data, pattern):
for n, elt in enumerate(a):
if elt[:3] == pattern:
yield n
indices = find_index(a, pattern)
next(indices)
It gives:
1
Here's a fairly simple and straightforward way of accomplishing this:
def findListMatch(lists, match):
# Loop over lists with indices
for k, sublist in enumerate(lists):
# Check if the beginning of the list matches the desired start pattern
if sublist[0:len(match)] == match:
# If it's a match, return the index
return k
# If none of the lists match, return a placeholder value of "None"
return None
a = [['1','2','3','a','b'],
['4','5','6','c','d'],
['7','8','9','e','f']]
matchIndex = findListMatch(a, ['4', '5', '6'])
# Result:
# matchIndex = 1
#U12-Forward's answer works but unnecessarily builds a temporary list of the same size as the input list before applying the index method, which can be quite an overhead if the list is long. A more efficient approach would be to use enumerate to generate the indices while comparing the first 3 items to the desired list:
next(i for i, l in enumerate(a) if l[:3] == ['4', '5', '6'])
I have the following 'numbers', which are actually strings from a regex:
nums = ['1', '4', '9', '10']
I would like to get the max, which would be 10. Is there a cleaner way to do this than to do a list comprehension, such as:
>>> max(nums)
'9'
>>> max([int(item) for item in nums])
10
Otherwise, it would give me 9.
max has a keyword argument key that takes a callable which transforms the values in some way before comparing them.
>>> max(nums, key=int)
This is essentially the same as your list comprehension max(int(item) for item in nums), except that it's important to note that the original values are returned, not the transformed values. This means that:
>>> a = max(nums, key=int)
>>> b = max(int(item) for item in nums)
>>> repr(a), repr(b)
('10', 10)
Use the map function:
>>> max(map(int, nums))
I have some troubles in merging two list of lists to one. I think there is a simple solution, but I'm stuck for hours.
My two list of lists are for example:
a=[['1','2'],['3','4']]
b=[['5','6'],['7','8']]
And what I try to get is:
c=[['1','2','5','6'],['3','4','7','8']]
But I don't know how many rows and columns the lists have.
I tried to use the zip command but it produced something like:
[(['1','2'],['5','6']),(['3','4'],['7','8'])]
Thanks very much for any help on this issue!!!
Maybe something like How can I add an additional row and column to an array? would work but I suppose there is an simpler solution.
>>> a=[['1','2'],['3','4']]
>>> b=[['5','6'],['7','8']]
>>> [x + y for x, y in zip(a, b)]
[['1', '2', '5', '6'], ['3', '4', '7', '8']]
[sum(ai_bi, []) for ai_bi in zip(a, b)]
which scales to n lists of lists :
L = (a, b, ...)
[sum(el, []) for el in zip(*L)]
If the two lists are of the same length, you could use a simple loop:
listone = [['1','2'],['3','4']]
listtwo = [['5','6'],['7','8']]
newlist = []
for i in range(0, len(data)):
newlist.append(listone[i] + listtwo[i])
print(newlist)
[['1','2','5','6'],['3','4','7','8']]
If your lists have the same lenght:
c = []
for idx in range(len(a)):
c.append(a[idx]+b[idx])
Not very elegant though.
How do you find the length of a multi-dimensional list?
I've come up with a way myself, but is this the only way to find the number of values in a multi-dimensional list?
multilist = [['1', '2', 'Ham', '4'], ['5', 'ABCD', 'Foo'], ['Bar', 'Lu', 'Shou']]
counter = 0
for minilist in multilist:
for value in minilist:
counter += 1
print(counter)
I'm pretty sure there is a much simpler way to find the length of a multi-dimensional list, but len(list) does not work, as it only gives the number of lists inside. Is there a more efficient method than this?
How about:
sum(len(x) for x in multilist)
Alternative to #mgilson's solution
sum(map(len, multilist))
If you want the number of items in any n-dimensional list then you need to use a recursive function like this:
def List_Amount(List):
return _List_Amount(List)
def _List_Amount(List):
counter = 0
if isinstance(List, list):
for l in List:
c = _List_Amount(l)
counter+=c
return counter
else:
return 1
This will return the number of items in the list no matter the shape or size of your list
Another alternative (it's this or watch missed math lectures...)
def getLength(element):
if isinstance(element, list):
return sum([getLength(i) for i in element])
return 1
This allows different degrees of 'multi-dimensionality' (if that were a word) to coexist.
eg:
>>> getLength([[1,2],3,4])
4
Or, to allow different collection types
def getLength(element):
try:
element.__iter__
return sum([getLength(i) for i in element])
except:
return 1
eg:
>>> getLength([ 1, 2, (1,3,4), {4:3} ])
6
>>> getLength(["cat","dog"])
2
(Noting that although strings are iterable, they do not have the __iter__ method-wrapper and so will not cause any issues...)
basically what the title says. I want to be able to find out how many objects a list contains. Maybe my Google-fu is failing me or my terminology is wrong.
len(s)
Return the length (the number of items) of an object. The argument may be a sequence (string, tuple or list) or a mapping (dictionary).
>>> l = [1, 2, 3]
>>> len(l)
3
Check out the len built-in function:
len(someList)
http://docs.python.org/library/functions.html#len
a = ['1', '2', '3']
print len(a)
This wiil print:
3