簡體   English   中英

從字典列表中創建非矛盾項的字典

[英]Create a dictionary of non-contradicting items from a list of dictionaries

這個問題的靈感來自於這個問題 我想從字典列表中獲取一個字典,該字典應該包含所有字典中的所有鍵/值對,這些字典只包含一次,或者所有字典都對相關值達成一致。 示例(摘自上述帖子):

dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)]
print dict_itersection(dicts)

應該屈服

{'a': 3, 'd': 2}

我目前的實現如下:

import collections

def dict_intersection(dicts):
        c=collections.defaultdict(set)
        for d in dicts:
                for a, b in d.iteritems():
                        c[a].add(b)
        return {a: next(iter(b)) for a, b in c.iteritems() if len(b) == 1}

所以我的問題是: 這可以更優雅地完成嗎?

Sidequestion:可以next(iter(b))不修改基礎字典(即不是b.pop() )的情況下更好地完成next(iter(b)) b.pop() )嗎?

你的非常接近我能想到的優雅。 我要做的唯一改變是用itertools.chain() 'ed迭代器替換嵌套的for循環,如下所示:

import collections

def dict_intersection(dicts):
        c=collections.defaultdict(set)
        for k,v in itertools.chain(*[d.iteritems() for d in dicts]):
                c[k].add(v)
        return {a: next(iter(b)) for a, b in c.iteritems() if len(b) == 1}

編輯(1):下面的代碼回答了一個稍微不同的問題 - 如何獲得在至少兩個輸入詞典中出現的具有相同鍵和值的任何條目。

我在另一個問題的評論中回答:

dict(
    [k for k,count in
     collections.Counter(itertools.chain(*[d.iteritems() for d in dicts])).iteritems()
     if count > 1]
    )

這名義上是一個“單行”,但我已經將它分散到多行(希望)使它更清晰一點。

它的工作方式是(從內部開始計算):

  • 使用itertools.chain()獲取所有字典元素的迭代器。
  • 使用collections.Counter()計算每個key, value對在字典中出現的次數。
  • 使用列表推導過濾Counter以便至少出現兩次key, value對。
  • 將列表轉換回dict。
dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)]

data = {}
for d in dicts:
    for k, v in d.iteritems():
        data.setdefault(k, set()).add(v)
out = dict((k, v.pop()) for k, v in data.iteritems() if len(v) == 1)

# out == {'a': 3, 'd': 2}

......或者單行:

import itertools as it

dict((k, v.pop()[1]) for k,v in ((k, set(v)) for k, v in it.groupby(sorted(it.chain(*(d.iteritems() for d in dicts))), key=lambda x: x[0])) if len(v) == 1)

到目前為止,所有解決方案都假設所有字典值都是可清 如果沒有這個假設,代碼不會變慢,只會變得更復雜,我會放棄它。 這是一個適用於所有支持的值的版本!=

def dict_intersection(dicts):
    result = {}
    conflicting = set()
    for d in dicts:
        for k, v in d.iteritems():
            if k not in conflicting and result.setdefault(k, v) != v:
                del result[k]
                conflicting.add(k)
    return result

設置conflicting只包含字典鍵,它始終是可清除的。

得到交集:

dict(reduce(lambda x, y: x & y, map(set, map(lambda x: x.iteritems(), dicts))))

當然,這會降低唯一值,所以我們需要得到補充:

dict(reduce(lambda x, y: x - y, map(set, map(lambda x: x.iteritems(), dicts))))

結合生成的詞典為我們提供了結果集:

def dict_intersection(d):
    x = dict(reduce(lambda x, y: x & y, map(set, map(lambda x: x.iteritems(), dicts))))
    y = dict(reduce(lambda x, y: x - y, map(set, map(lambda x: x.iteritems(), dicts))))
    return dict(x.items() + y.items())

如果我的設置更強,我可以把它降到一個班輪,但今天似乎沒有。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM