字典列表,按列表键分组,没有交集

Posted

技术标签:

【中文标题】字典列表,按列表键分组,没有交集【英文标题】:List of dicts, group without intersection by list keys 【发布时间】:2020-12-03 17:48:05 【问题描述】:

我需要帮助来优化我的代码。

我有一个数据:

data = [
  "ids": [1],
  "ids": [3, 4],
  "ids": [1, 2],
  "ids": [2],
]

并且我需要将其分组而不按 id 进行交叉,因此预期的数据应该是:

expected = [
  ["ids": [1], "ids": [2]],
  ["ids": [3, 4], "ids": [1, 2]],
]  # only 2 sublist here

我要拆分的代码(未优化):

import itertools as it

def _split(
    list_of_dicts,
):
    splitted_list_of_dicts = []
    sub_list = []
    while list_of_dicts:
        for dct in list_of_dicts:
            ids_in_sub_list = set(
                it.chain(*[sub_list_el["ids"] for sub_list_el in sub_list]),
            )
            if not set(dct["ids"]).intersection(ids_in_sub_list):
                sub_list.append(dct)
                list_of_dicts.remove(dct)
        splitted_list_of_dicts.append(sub_list)
        sub_list = []
    return splitted_list_of_dicts

我的代码的结果是:

result = [
    ['ids': [1], 'ids': [2]],
    ['ids': [3, 4]],
    ['ids': [1, 2]]
]  # 3 sublist

我又得到一个列表,我尝试对其进行优化。 如果您对如何帮助我有任何想法,我会很高兴,感谢您的宝贵时间。

更多示例:

data = [
  "ids": [1],
  "ids": [3, 4],
  "ids": [1, 2],
  "ids": [4],
  "ids": [3],
  "ids": [2],
]

可以分组为2个元素列表:

expected = [
    ['ids': [1], 'ids': [4], 'ids': [2], 'ids': [3]],
    ['ids': [3, 4], 'ids': [1, 2]],
]

但现在我得到了全部 4 个:

result = [
    ['ids': [1], 'ids': [4], 'ids': [2]],
    ['ids': [3, 4]],
    ['ids': [1, 2]],
    ['ids': [3]]
]

【问题讨论】:

你能保证在给定的输入中总是有偶数个元素吗? 不,这只是一个示例数据。元素的数量可以是任意的。 你还有更多的例子吗?我仍然不确定您应该如何对数据进行分组。 所以您想查看所有数据并做出没有任何相交ID的最佳分组? [1, 2] and [3, 4] 分组在一起的原因是什么? 【参考方案1】:

如果可以接受任何不包含重复项的组合,您可以简单地遍历 data 列表并将当前元素附加到结果中不存在任何 id 的第一个元素。

def split(list_of_dicts):
    result_helper = [set()] # This will be a list of sets for easy membership checks
    result_list = [[]] # This will be what we return
    for d in list_of_dicts:
        for s, l, in zip(result_helper, result_list):
            if not any(x in s for x in d["ids"]):
                s.update(d["ids"])
                l.append(d)
                break
        else:
            # for loop ended without being broken
            # This means no elements of result_list took this dict item. 
            # So create a new element
            result_list.append([d])
            result_helper.append(set(d["ids"]))
    return result_list

使用您的原始数据,

data = [
  "ids": [1],
  "ids": [3, 4],
  "ids": [1, 2],
  "ids": [2],
]
split(data)

我们得到输出:

 [
    ['ids': [1], 'ids': [3, 4], 'ids': [2]],
    ['ids': [1, 2]]
 ]

这似乎是一个可以接受的解决方案,因为所有列表都没有重复的 id。

还有第二个例子:

data = [
  "ids": [1],
  "ids": [3, 4],
  "ids": [1, 2],
  "ids": [4],
  "ids": [3],
  "ids": [2],
]
split(data)

这给出了输出:

 [
    ['ids': [1], 'ids': [3, 4], 'ids': [2]],
    ['ids': [1, 2], 'ids': [4], 'ids': [3]]
 ]

在这种情况下也没有重复。

【讨论】:

谢谢,伙计,你真是个天才。这正是我所需要的。【参考方案2】:

据我所知,您实际上是在对每个组的基数进行排序。

from itertools import groupby


def transform(data):
    cardinality = lambda x: len(x['ids'])
    sorted_data = sorted(data, key=cardinality)
    return [list(group) for _, group in groupby(sorted_data, key=cardinality)]

给予:

[
    [
        'ids': [1],
        'ids': [4],
        'ids': [3],
        'ids': [2]
    ],
    [
        'ids': [3, 4],
        'ids': [1, 2]
    ]
]

【讨论】:

嘿,谢谢你的时间,但我需要保存我原来的听写。 如果我们使用像:[ "ids": [1], "ids": [3, 4], "ids": [1, 2], "ids": [5], "ids": [3], "ids": [2], "ids": [2, 3], ] 这样的数据,结果数据将有重复:['ids': [[1], [5], [3], [2]], 'ids': [[3, 4], [1, 2], [2, 3]]] 可能有点晚了,但我想我现在明白了。也学了一点。

以上是关于字典列表,按列表键分组,没有交集的主要内容,如果未能解决你的问题,请参考以下文章

Python中多个词典和列表字典的高效快速数据存储和处理,以及列表的两个词典的交集

如何按列对pyspark中的数据框进行分组并以该列作为键并以记录列表作为其值来获取字典?

获取数据框列表并按变量分组,并使用该变量作为字典的键

集合关系运算符

如何根据两个时间范围列表的交集创建时间范围列表?

按两个参数对字典列表进行分组并计算分组值