Python 通过匹配列表中两个子元素的位置对列表中的元组进行分组

Python 通过匹配列表中两个子元素的位置对列表中的元组进行分组,python,list,group-by,grouping,itertools,Python,List,Group By,Grouping,Itertools,我有一个元组列表,如下所示。元组本身是一个嵌套的元组,其中包含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')), (

我有一个元组列表,如下所示。元组本身是一个嵌套的元组,其中包含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'))]
 ]

我尝试使用并检查了一些其他示例,但未能成功接近所需的输出。因此,任何帮助或建议都将不胜感激。

我的分组任务解决方案如下。我已经写了一个关于分组的长篇回答,你可以阅读。从答案中找出相关的片段,我们可以得到以下代码:

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

另一种方法是使用每对子项的位置作为键来制作字典

给定的

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()
代码

首先,我们构建了一个索引列表,用于在
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)]
最后,是使用自定义键和值生成
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
用于生成属于
白名单
项集的项的索引。这些结果足以将项目分组在一起。但是,更容易看到返回的实际项目,因此接下来我们使用
map\u reduce
构建一个字典


我们迭代了一组
(索引、可重用项)
keyfunc
索引转换为键。同样,
valuefunc
iterables
转换为值。如果有两个元组,
apple
mango

('a','apple'),('m','mango'),('a','apple'),('m','mango'),
('m','mango'),('a','apple'))
一样交换
('m','mango'),('a','apple'),
,则结果是一个
defaultdict
,这两个元组是否应该组合在一起?那么它们应该分为不同的组,因为苹果和芒果在第一个元组中的位置是1和2,在第二个元组中的位置是2和1!非常感谢您对您的方法和解决方案的详细解释。它确实帮助了我,作为一个例子,我强调了这是一个基本的例子,以便任何想要帮助的人都能理解它。但是,您的方法帮助我调整了“else部分”,以便对嵌套元组列表中的其他元组元素进行高级分组,如下例所示!group=tuple((t[1]如果t[1]在{'apple','mango'}中,否则t[0]),表示t在值)最后,为了更大的Python开发人员社区的利益,我重视并感谢您的知识共享能力谢谢!:)这也是解决这个问题的一种有趣的方法,尽管我已经使用了@aran提到的解决方案,因为它使我能够调整其他元组元素以进行高级分组。这很好。只需注意,对最终结果的任何调整都可能通过
map\u reduce
的关键字参数来完成,即
keyfunc
valuefunc
reducefunc.
是的,当然!Map_reduce是另一种选择。:)