Find an element in a list of tuples - python

I have a list 'a'
a= [(1,2),(1,4),(3,5),(5,7)]
I need to find all the tuples for a particular number. say for 1 it will be
result = [(1,2),(1,4)]
How do I do that?

If you just want the first number to match you can do it like this:
[item for item in a if item[0] == 1]
If you are just searching for tuples with 1 in them:
[item for item in a if 1 in item]

There is actually a clever way to do this that is useful for any list of tuples where the size of each tuple is 2: you can convert your list into a single dictionary.
For example,
test = [("hi", 1), ("there", 2)]
test = dict(test)
print test["hi"] # prints 1

Read up on List Comprehensions
[ (x,y) for x, y in a if x == 1 ]
Also read up up generator functions and the yield statement.
def filter_value( someList, value ):
for x, y in someList:
if x == value :
yield x,y
result= list( filter_value( a, 1 ) )

[tup for tup in a if tup[0] == 1]

for item in a:
if 1 in item:
print item

The filter function can also provide an interesting solution:
result = list(filter(lambda x: x.count(1) > 0, a))
which searches the tuples in the list a for any occurrences of 1. If the search is limited to the first element, the solution can be modified into:
result = list(filter(lambda x: x[0] == 1, a))

Or takewhile, ( addition to this, example of more values is shown ):
>>> a= [(1,2),(1,4),(3,5),(5,7),(0,2)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,a))
[(1, 2), (1, 4)]
>>>
if unsorted, like:
>>> a= [(1,2),(3,5),(1,4),(5,7)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,sorted(a,key=lambda x: x[0]==1)))
[(1, 2), (1, 4)]
>>>

Using filter function:
>>> def get_values(iterables, key_to_find):
return list(filter(lambda x:key_to_find in x, iterables))
>>> a = [(1,2),(1,4),(3,5),(5,7)]
>>> get_values(a, 1)
>>> [(1, 2), (1, 4)]

>>> [i for i in a if 1 in i]
[(1, 2), (1, 4)]

if you want to search tuple for any number which is present in tuple then you can use
a= [(1,2),(1,4),(3,5),(5,7)]
i=1
result=[]
for j in a:
if i in j:
result.append(j)
print(result)
You can also use if i==j[0] or i==j[index] if you want to search a number in particular index

Related

Find out if a tuple is contained into another one with repetitions in Python

Tuple1 = (1,2,2)
TupleList = [(1,2,3), (1,2,3,2)]
I want to search in TupleList for any tuple being a superset of Tuple1. The result should be in this case:
(1,2,3,2)
But if I use the .issuperset() function, it will not take into account the repetition of the 2 inside Tuple1.
How to solve this problem?
If you need to consider element frequency this is probably a good use of the collections.Counter utility.
from collections import Counter
tuple_1 = (1, 2, 2)
tuple_list = [(1, 2, 3), (3, 4, 1), (1, 2, 3, 2)]
def find_superset(source, targets):
source_counter = Counter(source)
for target in targets:
target_counter = Counter(target)
if is_superset(source_counter, target_counter):
return target
return None # no superset found
def is_superset(source_counter, target_counter):
for key in source_counter:
if not target_counter[key] >= source_counter[key]:
return False
return True
print(find_superset(tuple_1, tuple_list))
Output:
(1, 2, 3, 2)
from collections import Counter
def contains(container, contained):
" True if all values in dictionary container >= values in contained"
return all(container[x] >= contained[x] for x in contained)
def sublist(lst1, lst2):
" Detects if all elements in lst1 are in lst2 with at least as many count "
return contains(Counter(lst1), Counter(lst2), )
Tuple1 = (1,2,2)
TupleList = [(1,2,3), (1,2,3,2)]
# List of tuples from TupleList that contains Tuple1
result = [x for x in TupleList if sublist(x, Tuple1)]
print(result)
>>>[(1, 2, 3, 2)]

How can I count repetitive array in numpy?

X = [[1,2], [5,1], [1,2], [2,-1] , [5,1]]
I want to count "frequency" of repetitive elements for example [1,2]
Unless speed is really an issue, the simplest approach is to map the sub arrays to tuples and use a Counter dict:
X = [[1,2], [5,1], [1,2], [2,-1] , [5,1]]
from collections import Counter
cn = Counter(map(tuple, X))
print(cn)
print(list(filter(lambda x:x[1] > 1,cn.items())))
Counter({(1, 2): 2, (5, 1): 2, (2, -1): 1})
((1, 2), 2), ((5, 1), 2)]
If you consider [1, 2]equal to [2, 1] then you could use a frozenset Counter(map(frozenset, X)
Take a look at numpy.unique: http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.unique.html
You can use the return_counts argument for getting the count of each item:
values, counts = numpy.unique(X, return_counts = True)
repeated = values[counts > 1]
Assuming I understand what you want:
Try to count each item in your list into a dictionary dict then select from dict items that its count > 1
The following code might help you:
freq = dict()
for item in x:
if tuple(item) not in x:
freq[tuple(item)] = 1
else:
freq[tuple(item)] += 1
print {k:v for(k,v) in freq.items() if v > 1}
That code will give you the output:
{(1, 2): 2}

compare to lists and return the different indices and elements in python

I want to compare to lists and return the different indices and elements.
So I write the following code:
l1 = [1,1,1,1,1]
l2 = [1,2,1,1,3]
ind = []
diff = []
for i in range(len(l1)):
if l1[i] != l2[i]:
ind.append(i)
diff.append([l1[i], l2[i]])
print ind
print diff
# output:
# [1, 4]
# [[1, 2], [1, 3]]
The code works, but are there any better ways to do that?
Update the Question:
I want to ask for another solutions, for example with the iterator, or ternary expression like [a,b](expression) (Not the easiest way like what I did. I want to exclude it.) Thanks very much for the patient! :)
You could use a list comprehension to output all the information in a single list.
>>> [[idx, (i,j)] for idx, (i,j) in enumerate(zip(l1, l2)) if i != j]
[[1, (1, 2)], [4, (1, 3)]]
This will produce a list where each element is: [index, (first value, second value)] so all the information regarding a single difference is together.
An alternative way is the following
>>> l1 = [1,1,1,1,1]
>>> l2 = [1,2,1,1,3]
>>> z = zip(l1,l2)
>>> ind = [i for i, x in enumerate(z) if x[0] != x[1]]
>>> ind
[1, 4]
>>> diff = [z[i] for i in ind]
>>> diff
[(1, 2), (1, 3)]
In Python3 you have to add a call to list around zip.
You can try functional style:
res = filter(lambda (idx, x): x[0] != x[1], enumerate(zip(l1, l2)))
# [(1, (1, 2)), (4, (1, 3))]
to unzip res you can use:
zip(*res)
# [(1, 4), ((1, 2), (1, 3))]

Comparing items within a list with each other

If I have a list
lst = [1, 2, 3, 4, 5]
and I want to show that two items exist one of which is larger than the other by 1, can I do this without specifying which items in the list?
ie. without having to do something like:
lst[1] - lst[0] == 1
a general code that works for any int items in the lst
You can pair the numbers if the one less than the number is in the list:
new = [(i, i - 1) for i in lst if i - 1 in lst]
This one: makes set of the list for faster member checks; then short circuiting checks if i + 1 exists in that set for each i in the list (I iterate over list instead of the newly created set because it should be slightly faster). As soon as it is proven that any i + 1 also is in the list, the function exits with True return value, False otherwise.
def has_n_and_n_plus_1(lst):
lset = set(lst)
return any(i + 1 in lset for i in lst)
Testing:
>>> has_n_and_n_plus_1([6,2,7,11,42])
True
>>> has_n_and_n_plus_1([6,2,9,11,42])
False
The all tricks in 1 basket brain-teaser one:
from operator import sub
from itertools import starmap, tee
a, b = tee(sorted(lst))
next(b, None)
exists = 1 in starmap(sub, zip(b, a))
What this code does is: sort the list in increasing order; then do the pairwise iteration of a, b = lst[i], lst[i + 1], then starmaps each b, a into the sub operator resulting in b - a; and then checks with in operator if that resulting iterator contains any 1.
You could zip the list with itself shifted by one.
>>> lst = [1,2,3,4,5]
>>> zip(lst, lst[1:])
[(1, 2), (2, 3), (3, 4), (4, 5)]
This assumes that the list is ordered. If it is not, then you could sort it first and then filter it to exclude non matches (perhaps including the indexes in the original list if that is important). So if it's a more complex list of integers this should work:
>>> lst = [99,12,13,44,15,16,45,200]
>>> lst.sort()
>>> [(x,y) for (x,y) in zip(lst, lst[1:]) if x + 1 == y]
[(12, 13), (15, 16), (44, 45)]
The following is the equivalent using functions. The use of izip from itertools ensure the list is only iterated over once when we are looking for matches with the filter function:
>>> from itertools import izip
>>> lst = [99,12,13,44,15,16,45,200]
>>> lst.sort()
>>> filter(lambda (x,y): x+1==y, izip(lst, lst[1:]))
[(12, 13), (15, 16), (44, 45)]
The same could be written using for comprehensions, but personally I prefer using functions.

How to get first element in a list of tuples?

I have a list like below where the first element is the id and the other is a string:
[(1, u'abc'), (2, u'def')]
I want to create a list of ids only from this list of tuples as below:
[1,2]
I'll use this list in __in so it needs to be a list of integer values.
>>> a = [(1, u'abc'), (2, u'def')]
>>> [i[0] for i in a]
[1, 2]
Use the zip function to decouple elements:
>>> inpt = [(1, u'abc'), (2, u'def')]
>>> unzipped = zip(*inpt)
>>> print unzipped
[(1, 2), (u'abc', u'def')]
>>> print list(unzipped[0])
[1, 2]
Edit (#BradSolomon):
The above works for Python 2.x, where zip returns a list.
In Python 3.x, zip returns an iterator and the following is equivalent to the above:
>>> print(list(list(zip(*inpt))[0]))
[1, 2]
do you mean something like this?
new_list = [ seq[0] for seq in yourlist ]
What you actually have is a list of tuple objects, not a list of sets (as your original question implied). If it is actually a list of sets, then there is no first element because sets have no order.
Here I've created a flat list because generally that seems more useful than creating a list of 1 element tuples. However, you can easily create a list of 1 element tuples by just replacing seq[0] with (seq[0],).
I was thinking that it might be useful to compare the runtimes of the different approaches so I made a benchmark (using simple_benchmark library)
I) Benchmark having tuples with 2 elements
As you may expect to select the first element from tuples by index 0 shows to be the fastest solution very close to the unpacking solution by expecting exactly 2 values
import operator
import random
from simple_benchmark import BenchmarkBuilder
b = BenchmarkBuilder()
#b.add_function()
def rakesh_by_index(l):
return [i[0] for i in l]
#b.add_function()
def wayneSan_zip(l):
return list(list(zip(*l))[0])
#b.add_function()
def bcattle_itemgetter(l):
return list(map(operator.itemgetter(0), l))
#b.add_function()
def ssoler_upacking(l):
return [idx for idx, val in l]
#b.add_function()
def kederrack_unpacking(l):
return [f for f, *_ in l]
#b.add_arguments('Number of tuples')
def argument_provider():
for exp in range(2, 21):
size = 2**exp
yield size, [(random.choice(range(100)), random.choice(range(100))) for _ in range(size)]
r = b.run()
r.plot()
II) Benchmark having tuples with 2 or more elements
import operator
import random
from simple_benchmark import BenchmarkBuilder
b = BenchmarkBuilder()
#b.add_function()
def kederrack_unpacking(l):
return [f for f, *_ in l]
#b.add_function()
def rakesh_by_index(l):
return [i[0] for i in l]
#b.add_function()
def wayneSan_zip(l):
return list(list(zip(*l))[0])
#b.add_function()
def bcattle_itemgetter(l):
return list(map(operator.itemgetter(0), l))
#b.add_arguments('Number of tuples')
def argument_provider():
for exp in range(2, 21):
size = 2**exp
yield size, [tuple(random.choice(range(100)) for _
in range(random.choice(range(2, 100)))) for _ in range(size)]
from pylab import rcParams
rcParams['figure.figsize'] = 12, 7
r = b.run()
r.plot()
This is what operator.itemgetter is for.
>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b
[1, 2]
The itemgetter statement returns a function that returns the element at the index that you specify. It's exactly the same as writing
>>> b = map(lambda x: x[0], a)
But I find that itemgetter is a clearer and more explicit.
This is handy for making compact sort statements. For example,
>>> c = sorted(a, key=operator.itemgetter(0), reverse=True)
>>> c
[(2, u'def'), (1, u'abc')]
You can use "tuple unpacking":
>>> my_list = [(1, 'abc'), (2, 'def')]
>>> my_ids = [idx for idx, val in my_list]
>>> my_ids
[1, 2]
At iteration time each tuple is unpacked and its values are set to the variables idx and val.
>>> x = (1, 'abc')
>>> idx, val = x
>>> idx
1
>>> val
'abc'
if the tuples are unique then this can work
>>> a = [(1, u'abc'), (2, u'def')]
>>> a
[(1, u'abc'), (2, u'def')]
>>> dict(a).keys()
[1, 2]
>>> dict(a).values()
[u'abc', u'def']
>>>
From a performance point of view, in python3.X
[i[0] for i in a] and list(zip(*a))[0] are equivalent
they are faster than list(map(operator.itemgetter(0), a))
Code
import timeit
iterations = 100000
init_time = timeit.timeit('''a = [(i, u'abc') for i in range(1000)]''', number=iterations)/iterations
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = [i[0] for i in a]''', number=iterations)/iterations - init_time)
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = list(zip(*a))[0]''', number=iterations)/iterations - init_time)
output
3.491014136001468e-05
3.422205176000717e-05
when I ran (as suggested above):
>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b
instead of returning:
[1, 2]
I received this as the return:
<map at 0xb387eb8>
I found I had to use list():
>>> b = list(map(operator.itemgetter(0), a))
to successfully return a list using this suggestion. That said, I'm happy with this solution, thanks. (tested/run using Spyder, iPython console, Python v3.6)
I'd prefer zipping this way:
>>> lst = [(1, u'abc'), (2, u'def')]
>>> new, _ = zip(*lst)
>>> new
(1, 2)
>>>
Or if you don't know how many extra values there are:
>>> new, *_ = zip(*lst)
>>> new
(1, 2)
>>>
you can unpack your tuples and get only the first element using a list comprehension:
l = [(1, u'abc'), (2, u'def')]
[f for f, *_ in l]
output:
[1, 2]
this will work no matter how many elements you have in a tuple:
l = [(1, u'abc'), (2, u'def', 2, 4, 5, 6, 7)]
[f for f, *_ in l]
output:
[1, 2]
I wondered why nobody suggested to use numpy, but now after checking i understand. It is maybe not the best for mixed type arrays.
This would be a solution in numpy:
>>> import numpy as np
>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
To get an element of a list or tuple you can iterate through a list or tuple
a = [(1, u'abc'), (2, u'def')]
list1 = [a[i][0] for i in range(len(a))]
print(list1)
Those are tuples, not sets. You can do this:
l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]
another simple suggestion if you need to convert to a nested of the tuple, and all elements inside the list the answer will be:
s=[]
for i in range(len(a)):
s.append(a[i][0])
print(s)
Output:
[(1),(2)]
If you need to convert to a nested of the list, the answer will be:
a = [(1, u'abc'), (2, u'def')]
print([list(i[0]) for i in a])
output:
[[1], [2]]
Solution using list comprehension.
og_list = [(1, u'abc'), (2, u'def')]
list_of_keys = [key for key, _ in og_list]
output
[1,2]

Categories

Resources