KianFakheriAghdam
KianFakheriAghdam

Reputation: 166

How to keep repeated values in a tuple of tuples

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.

Upvotes: 1

Views: 241

Answers (5)

Vitalizzare
Vitalizzare

Reputation: 7240

(*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:])

Upvotes: 1

Deepak Tripathi
Deepak Tripathi

Reputation: 3243

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)])

Upvotes: 1

itprorh66
itprorh66

Reputation: 3288

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}

Upvotes: 1

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 96172

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

reduce(frozenset.intersection, map(frozenset, data))

Upvotes: 2

Mark
Mark

Reputation: 92460

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.

Upvotes: 2

Related Questions