Группируйте кортежи внутри списка, сопоставляя позиции двух его подэлементов - PullRequest
0 голосов
/ 05 июля 2018

У меня есть список кортежей, как показано ниже. Кортеж сам по себе является вложенным кортежем с 3 подэлементами (кортежами) внутри него.

[(('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('e', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('a', 'apple'), ('d', 'mango'), ('c', 'peach')),
 (('e', 'apple'), ('d', 'mango'), ('f', 'grapes')),
 (('f', 'grapes'), ('e', 'apple'), ('d', 'mango')),
 (('f', 'peach'), ('e', 'apple'), ('e', 'mango')),
 (('f', 'grapes'), ('c', 'apple'), ('d', 'mango')), 
 (('e', 'apple'), ('f', 'grapes'), ('d', 'mango')),
 (('a', 'apple'), ('c', 'grapes'), ('b', 'mango')),
 ]

Я хочу сгруппировать эти кортежи, сопоставив позиции двух их элементов, а именно. Яблоко и манго (которые заранее известны и известны) внутри кортежей!

Желаемый вывод:

[
# apple and mango at positions 1 and 2.
[(('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('e', 'apple'), ('b', 'mango'), ('c', 'grapes')),
 (('a', 'apple'), ('d', 'mango'), ('c', 'peach')),
 (('e', 'apple'), ('d', 'mango'), ('f', 'grapes'))],

# apple and mango at positions 2 and 3.
 [(('f', 'grapes'), ('e', 'apple'), ('d', 'mango')),
 (('f', 'peach'), ('e', 'apple'), ('e', 'mango')),
 (('f', 'grapes'), ('c', 'apple'), ('d', 'mango'))], 

# apple and mango at positions 1 and 3.
 [(('e', 'apple'), ('f', 'grapes'), ('d', 'mango')),
 (('a', 'apple'), ('c', 'grapes'), ('b', 'mango'))]
 ]

Я попытался использовать Counter , а также проверил некоторые другие примеры, но не смог приблизиться к желаемому результату. Таким образом, любая помощь или указатели будут очень благодарны.

Ответы [ 2 ]

0 голосов
/ 07 июля 2018

Другой подход заключается в создании словаря, использующего позиции для каждой пары подпунктов в качестве ключей.

С учетом

import more_itertools as mit

iterables = [
     (("a", "apple"),  ("b", "mango"),  ("c", "grapes")),
     (("a", "apple"),  ("b", "mango"),  ("c", "grapes")),
     (("e", "apple"),  ("b", "mango"),  ("c", "grapes")),
     (("a", "apple"),  ("d", "mango"),  ("c", "peach")),
     (("e", "apple"),  ("d", "mango"),  ("f", "grapes")),
     (("f", "grapes"), ("e", "apple"),  ("d", "mango")),
     (("f", "peach"),  ("e", "apple"),  ("e", "mango")),
     (("f", "grapes"), ("c", "apple"),  ("d", "mango")), 
     (("e", "apple"),  ("f", "grapes"), ("d", "mango")),
     (("a", "apple"),  ("c", "grapes"), ("b", "mango")),
]

whitelisted = "apple mango".split()

Код

Сначала мы строим список индексов для locate вхождений whitelisted подпунктов в iterables.

pred = lambda x: x[1] in set(whitelisted)
indices = [tuple(mit.locate(t, pred=pred)) for t in iterables]
print(indices)
# [(0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (1, 2), (1, 2), (1, 2), (0, 2), (0, 2)]

Наконец, map_reduce - это один из способов сделать defaultdict с пользовательскими ключами и значениями.

result = mit.map_reduce(zip(indices, iterable), keyfunc=lambda x: x[0], valuefunc=lambda x: x[1])
result

выход

defaultdict(None,
            {(0, 1): [(('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
              (('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
              (('e', 'apple'), ('b', 'mango'), ('c', 'grapes')),
              (('a', 'apple'), ('d', 'mango'), ('c', 'peach')),
              (('e', 'apple'), ('d', 'mango'), ('f', 'grapes'))],
             (1, 2): [(('f', 'grapes'), ('e', 'apple'), ('d', 'mango')),
              (('f', 'peach'), ('e', 'apple'), ('e', 'mango')),
              (('f', 'grapes'), ('c', 'apple'), ('d', 'mango'))],
             (0, 2): [(('e', 'apple'), ('f', 'grapes'), ('d', 'mango')),
              (('a', 'apple'), ('c', 'grapes'), ('b', 'mango'))]})

Детали

Для каждого кортежа в iterables, locate используется для получения индексов для элементов, принадлежащих к набору whitelisted элементов. Эти результаты достаточны для группировки элементов вместе. Тем не менее, легче увидеть реальные возвращенные элементы, поэтому далее мы создаем словарь с map_reduce.

Итерируем zip из (indices, iterables) пар. keyfunc преобразует indices в качестве ключей. Аналогично, valuefunc преобразует iterables в значения. В результате получается defaultdict со значениями, сгруппированными по подпозициям из whitelisted элементов apple и mango.

0 голосов
/ 05 июля 2018

Моим подходящим решением для группировки задач, подобных этой, является collections.defaultdict. Я написал длинный ответ о группировке вещей, который вы можете прочитать здесь . Выбор соответствующих фрагментов из этого ответа дает нам этот фрагмент кода:

import collections

groupdict = collections.defaultdict(list)
for value in your_list_of_tuples:  # input
    group = ???  # group identifier
    groupdict[group].append(value)

result = list(groupdict.values())  # output

Все, что осталось, - это найти способ уникального представления каждой группы с хеш-значением (то есть нам нужно заполнить строку group = ???).

Самым простым решением, вероятно, является извлечение значений apple и mango из вложенных кортежей и замена всех остальных значений на None:

>>> tup = (('a', 'apple'), ('c', 'grapes'), ('b', 'mango'))
>>> tuple((t[1] if t[1] in {'apple','mango'} else None) for t in tup)
('apple', None, 'mango')

Добавьте это, и все готово:

import collections

groupdict = collections.defaultdict(list)
for value in your_list_of_tuples:
    group = tuple((t[1] if t[1] in {'apple','mango'} else None) for t in value)
    groupdict[group].append(value)

result = list(groupdict.values())

# result:
# [[(('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
#   (('a', 'apple'), ('b', 'mango'), ('c', 'grapes')),
#   (('e', 'apple'), ('b', 'mango'), ('c', 'grapes')),
#   (('a', 'apple'), ('d', 'mango'), ('c', 'peach')),
#   (('e', 'apple'), ('d', 'mango'), ('f', 'grapes'))],
#  [(('f', 'grapes'), ('e', 'apple'), ('d', 'mango')),
#   (('f', 'peach'), ('e', 'apple'), ('e', 'mango')),
#   (('f', 'grapes'), ('c', 'apple'), ('d', 'mango'))],
#  [(('e', 'apple'), ('f', 'grapes'), ('d', 'mango')),
#   (('a', 'apple'),('c', 'grapes'), ('b', 'mango'))]]
...