获得最大对数而不重复使用dictricion密钥

时间:2018-05-02 10:05:06

标签: python

我正在努力获得我的列表的最大利用率("削减" )。

我有一个字典列表,只要给定的 k2 不匹配,我希望获得" pares" 的最大数量。我想某种排列会缩小资源清单?

这是我得到的地方:

t = [ {'k1': 1, 'k2': 'a'},
      {'k1': 2, 'k2': 'a'},
      {'k1': 3, 'k2': 'b'},
      {'k1': 4, 'k2': 'b'},
      {'k1': 5, 'k2': 'c'},
      {'k1': 6, 'k2': 'd'},
      {'k1': 7, 'k2': 'a'},
      {'k1': 8, 'k2': 'd'}]

t2 = t[:]

for d in t2:
    for x in t2:
        if d['k2'] != x['k2']:
            print(d,x)
            t2.remove(x)
            t2.remove(d)
            break

问题是我留下了t2 = [{'k2': 'd', 'k1': 6}, {'k2': 'd', 'k1': 8}]

浪费1对手动我可以实现以下目标:

({'k2': 'a', 'k1': 1}, {'k2': 'b', 'k1': 3})
({'k2': 'b', 'k1': 4}, {'k2': 'a', 'k1': 2})
({'k2': 'd', 'k1': 6}, {'k2': 'c', 'k1': 5})
({'k2': 'a', 'k1': 7}, {'k2': 'd', 'k1': 8})

或类似总共4对。我在这里错过了一招吗?

更新

我需要的是每次创建一对时我需要从列表中删除项目,因此我只能手动执行此操作。

我不在乎"关心"关于巴黎,只要k2不匹配,我已经获得了最有效率对的列表,即在我上面的代码中我浪费 1个可能的对不使用字典 k2:d 因此这不是最有效的组合。

如果仍然不清楚,我会道歉,也许我说错了。

2 个答案:

答案 0 :(得分:2)

虽然我不完全确定,但感觉有bin packing problem。根据某些定义,您的垃圾箱可容纳2件具有独特价值的物品。然后问题陈述是尽量减少使用过的箱子的数量,或者换句话说,如果可能的话,避免生产仅包含1个箱子的箱子。

实施first-fit近似解决方案非常简单。它不会为所有值产生完美的结果,但恰好它会为您找到最佳解决方案:

def pairs(t, key):
    bins = []
    full = []

    for d in t:
        for i, (k, p) in enumerate(bins):
            if d[key] != k:
                p.append(d)
                full.append(p)
                # This is okay only because we do not continue
                # iterating after mutation.
                del bins[i]
                break

        else:
            # No bin could hold this d, so create a new one
            bins.append((d[key], [d]))

    return full

作为一项额外措施,您可以先按频率对值进行排序,使其成为首先适合下降的值:

def pairs(t, key):
    lookup = defaultdict(list)

    for d in t:
        lookup[d[key]].append(d)

    gs = sorted(lookup.values(), key=len, reverse=True)
    ds = [d for g in gs for d in g]

    bins = []
    full = []

    for d in ds:
        ...

    ...

答案 1 :(得分:1)

为了获得最大数量的可能对,您必须以智能方式创建对。考虑这样的输入:

k2_values = ['a', 'c', 'b', 'b']

如果您不打算正确构建对,可能最终会将ac配对,这会阻止您创建第二对,因为您只有2 {{1}离开了。要获得最大数量的对,您必须开始使用您最常用的值构建对 - 使用b

因此,第一步是按照b值对您的词典列表进行分组:

k2

然后按长度对这些组进行排序:

{'a': [{'k1': 1, 'k2': 'a'}, {'k1': 2, 'k2': 'a'}, {'k1': 7, 'k2': 'a'}],
 'b': [{'k1': 3, 'k2': 'b'}, {'k1': 4, 'k2': 'b'}],
 'c': [{'k1': 5, 'k2': 'c'}],
 'd': [{'k1': 6, 'k2': 'd'}, {'k1': 8, 'k2': 'd'}]}

最后从这些小组中建立对。

实施

[[{'k1': 1, 'k2': 'a'}, {'k1': 2, 'k2': 'a'}, {'k1': 7, 'k2': 'a'}],
 [{'k1': 3, 'k2': 'b'}, {'k1': 4, 'k2': 'b'}],
 [{'k1': 6, 'k2': 'd'}, {'k1': 8, 'k2': 'd'}],
 [{'k1': 5, 'k2': 'c'}]]

试运行:

import operator
import collections

def make_pairs(dicts, keyfunc):
    if isinstance(keyfunc, str):
        keyfunc = operator.itemgetter(keyfunc)

    # group the dicts by k2 values
    grouped_dicts = collections.defaultdict(list)
    for dic in dicts:
        key = keyfunc(dic)
        grouped_dicts[key].append(dic)

    # sort the groups by size
    grouped_dicts = sorted(grouped_dicts.values(), key=len, reverse=True)

    # iterate over the groups and build pairs
    iters = [(len(group), iter(group)) for group in grouped_dicts]
    iters_itr = iter(iters)

    len1, itr1 = next(iters_itr)
    for len2, itr2 in iters_itr:
        # make sure the shorter iterator comes first
        if len1 > len2:
            itr1, itr2 = itr2, itr1
            len1, len2 = len2, len1

        yield from zip(itr1, itr2)

        # discard the exhausted iterator and re-calculate
        # the remaining length
        itr1 = itr2
        len1 = len2 - len1