How to keep repeated values in a tuple of tuples

Question:

Let’s say I got something like ((1, 2), (2, 3), (2, 3)). As you can see, 2 is repeated across all of tuples in the tuple. I want something to return (2).

The real data set I’m working on is:

(
  (2, 3, 5, 7, 9),
  (2, 3, 4, 5, 7, 8, 10),
  (2, 3, 4, 5, 6, 7, 9, 10),
  (2, 3, 4, 5, 6, 7, 8, 9),
  (2, 3, 4, 5, 6, 7, 8, 9, 10),
  (2, 3, 4, 5, 6, 7, 8, 9, 10),
  (2, 3, 4, 5, 6, 7, 8, 9, 10),
  (2, 3, 4, 5, 6, 7, 8, 9, 10),
  (2, 3, 4, 5, 6, 7, 8, 9, 10)
)

And I’m excepting it to return (2, 3, 5, 7).

I have already tried the following, but it returns an empty tuple for some reason.

a = ((1, 2), (2, 3), (2, 3))
print(tuple(filter(lambda x: all(x in i for i in a), a)))

There are three things that are important to me.

  1. No usage of mutable data & statements
  2. As less for as possible, instead map or filter
  3. It should all be fit in one line, so I can turn it to a lambda function or so…

So basically, I want to do this functionally.

Asked By: KianFakheriAghdam

||

Answers:

You are taking a group of tuples and returning a single different tuple. So filter is not really what you want. If you are thinking about functional programming, this really seems like a problem for reduce

That might look like:

from functools import reduce

t = ((2, 3, 5, 7, 9), (2, 3, 4, 5, 7, 8, 10), (2, 3, 4, 5, 6, 7, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10))

reduce(lambda res, curr: tuple(n for n in res if n in curr), t)
# (2, 3, 5, 7)

Here you just create a single tuple res on each iteration, which contains values seen by all lists.

Answered By: Mark
(*set.intersection(*map(set, t)),)

p.s. Looks like I have to add some words to avoid labeling the answer as low quality. But the idea seems quite obvious: create sets from tuples and get their intersection.

Update

It seems that we could do without reduce or map by creating a set or frozen set once and providing iterables to its intersection method:

frozenset(t[0]).intersection(*t[1:])
Answered By: Vitalizzare

Using Counter

from itertools import chain
from collections import Counter
a = ((2, 3, 5, 7, 9), (2, 3, 4, 5, 7, 8, 10), (2, 3, 4, 5, 6, 7, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10), (2, 3, 4, 5, 6, 7, 8, 9, 10))
print([ele[0] for ele in Counter(chain(*a)).items() if ele[1]==len(a)])
Answered By: Deepak Tripathi

Here, using functools.reduce, you can do something like:

reduce(frozenset.intersection, map(frozenset, data))
Answered By: juanpa.arrivillaga

A slightly different approach:
Given:

from functools import reduce
a = ((1, 2), (2, 3), (2, 3))
def combo(a, b)
    return a&b
reduce(combo, [set(x) for x in a])

Yields {2}

Answered By: itprorh66
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.