我正在努力获得我的列表的最大利用率("削减" )。
我有一个字典列表,只要给定的 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 因此这不是最有效的组合。
如果仍然不清楚,我会道歉,也许我说错了。
答案 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']
如果您不打算正确构建对,可能最终会将a
和c
配对,这会阻止您创建第二对,因为您只有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