Python: if the first element is equal to a tuple along with other elements

Sorry if this was asked before, but I could not find it. If I have something like:

lst = [(('a', 'b'), 1, 2), (('a', 'b'), 3, 4), (('b', 'c'), 5, 6)]

and I want to get a shorter list:

new = [(('a', 'b'), (1, 3), (2, 4)), (('b', 'c'), 5, 6)]

to group the remaining elements together in a tuple using the first matching element, what is the fastest way to do this?

+4
source share
3 answers

You group based on the key. If your input groups are always consistent, you can use itertools.groupby(), otherwise use a dictionary to group items. If order matters, use a dictionary that preserves the insertion order (> Python 3.6 dictor collections.OrderedDict).

Usage groupby():

from itertools import groupby
from operator import itemgetter

new = [(k, *zip(*(t[1:] for t in g))) for k, g in groupby(lst, key=itemgetter(0))]

Python 3 (..., * iterable) `.

:

groups = {}
for key, *values in lst:
    groups.setdefault(key, []).append(values)
new = [(k, *zip(*v)) for k, v in groups.items()]

Python 3.6 .

:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> lst = [(('a', 'b'), 1, 2), (('a', 'b'), 3, 4), (('b', 'c'), 5, 6)]
>>> [(k, *zip(*(t[1:] for t in g))) for k, g in groupby(lst, key=itemgetter(0))]
[(('a', 'b'), (1, 3), (2, 4)), (('b', 'c'), (5,), (6,))]
>>> groups = {}
>>> for key, *values in lst:
...     groups.setdefault(key, []).append(values)
...
>>> [(k, *zip(*v)) for k, v in groups.items()]
[(('a', 'b'), (1, 3), (2, 4)), (('b', 'c'), (5,), (6,))]

Python 2, :

new = [(k,) + tuple(zip(*(t[1:] for t in g))) for k, g in groupby(lst, key=itemgetter(0))]

from collections import OrderedDict
groups = OrderedDict()
for entry in lst:
    groups.setdefault(entry[0], []).append(entry[1:])
new = [(k,) + tuple(zip(*v)) for k, v in groups.items()]
+4

collections.defaultdict, :

from collections import defaultdict

lst = [(('a', 'b'), 1, 2), (('a', 'b'), 3, 4), (('b', 'c'), 5, 6)]

d = defaultdict(tuple)
for tup, fst, snd in lst:
    d[tup] += fst, snd
# defaultdict(<class 'tuple'>, {('a', 'b'): (1, 2, 3, 4), ('b', 'c'): (5, 6)})

for key, value in d.items():
    d[key] = value[0::2], value[1::2]
# defaultdict(<class 'tuple'>, {('a', 'b'): ((1, 3), (2, 4)), ('b', 'c'): ((5,), (6,))})

result = [(k, v1, v2) for k, (v1, v2) in d.items()]

:

[(('a', 'b'), (1, 3), (2, 4)), (('b', 'c'), (5,), (6,))]

:

  • defaultdict .
  • [0::2] [1::2].
  • .
+1

defaultdict . .

from collections import defaultdict
listmaker = lambda: ([],[]) # makes a tuple of 2 lists for the values.
my_data = defaultdict(listmaker) 
for letter_tuple, v1, v2 in lst:
    my_data[letter_tuple][0].append(v1)
    my_data[letter_tuple][1].append(v2)

You will then receive a new set of lists for each unique key (x,y). Python processes the validation to make sure the key already exists and is fast. If you absolutely need this to be a list, you can always convert it:

new = [(k, tuple(v1s), tuple(v2s)) for k, (v1s, v2s) in my_data.items()]

This list comprehension is a bit opaque, but it will unpack your dictionary into the specified form [(('a', 'b'), (1,3), (2,4)), ... ]

0
source

Source: https://habr.com/ru/post/1693155/


All Articles