python efficient way to compare item in list of tuples

Question:

Is there an efficient way without for loops to compare if an item inside a list of tuples is the same across all tuples in Python?

lst_tups = [('Hello', 1, 'Name:'), ('Goodbye', 1, 'Surname:'), ('See you!', 1, 'Time:')]

The expected output is Return all unique values for item in index 1 of the tuple

unique = list()

for i in lst_tups:
    item = i[1]
    unique.append(item)


set(unique)
    

Expected Output: 
>>

Unique values: [1]

True if all are equal, otherwise False
Asked By: matt.aurelio

||

Answers:

You can use chain.from_iterable and slicing with three step : [1::3].

from itertools import chain
res = list(chain.from_iterable(lst_tups))[1::3]
print(set(res))

# If you want to print True if all are equal, otherwise False
if len(set(res)) == 1:
    print('True')
else:
    print('False')

{1}
Answered By: I'mahdi

Solution without using for loop.

import operator
lst_tups = [('Hello', 1, 'Name:'), ('Goodbye', 1, 'Surname:'), ('See you!', 1, 'Time:')]
unique = set(map(operator.itemgetter(1),lst_tups))
print(unique)  # {1}

Please consider above code and write if is an efficient way according to your standards.

Answered By: Daweo

I think the set comprehension is an acceptable way:

>>> unique = {i[1] for i in lst_tups}
>>> unique
{1}

If you want to avoid the for loop anyway, you can use operator.itemgetter and map (for large lists, it will be slightly more efficient than set comprehension, but the readability is worse):

>>> from operator import itemgetter
>>> unique = set(map(itemgetter(1), lst_tups))
>>> unique
{1}

Then you can confirm whether the elements are all the same by judging whether the length of the set is 1:

>>> len(unique) == 1
True

If you only want to get the result or the item you want to compare is unhashable (such as dict), you can use itertools.pairwise (in Python3.10+) to compare adjacent elements to judge (but that doesn’t mean it will be faster):

>>> from itertools import pairwise, starmap
>>> from operator import itemgetter, eq
>>> all(i[1] == j[1] for i, j in pairwise(lst_tups))
True
>>> all(starmap(eq, pairwise(map(itemgetter(1), lst_tups))))
True

According to the questions raised in the comment area, when your unique item is in another position or the element itself in the sequence, the above method only needs to be slightly modified to achieve the purpose, so here are two more general solutions:

def all_equal_by_set(iterable):
    return len(set(iterable)) == 1


def all_equal_by_compare(iterable):
    return all(starmap(eq, pairwise(iterable)))

Then you just need to call them like this:

>>> all_equal_by_set(map(itemgetter(1), lst_tups))
True
>>> all_equal_by_set(tup[1] for tup in lst_tups)   # Note that here is a generator expression, which is no longer comprehension.
True
>>> all_equal_by_compare(map(itemgetter(1), lst_tups))
True
>>> all_equal_by_compare(tup[1] for tup in lst_tups)
True
Answered By: Mechanic Pig
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.