簡體   English   中英

如果其中一個值不是唯一的,從字典列表中刪除元素的pythonic方法是什么?

[英]What's the pythonic way to remove element from a list of dict if ONE of the values is not unique?

刪除某些鍵不是唯一的元素的pythonic方法是什么?

假設一個人有一個字典列表,例如:

[
    {'a': 1, 'b': 'j'},
    {'a': 2, 'b': 'j'},
    {'a': 3, 'b': 'i'}
]

預期的 output 將刪除第二個元素,因為鍵b在多個元素中等於j 因此:

[
    {'a': 1, 'b': 'j'},
    {'a': 3, 'b': 'i'}
]

這是我嘗試過的:

input = [
    {'a': 1, 'b': 'j'},
    {'a': 2, 'b': 'j'},
    {'a': 3, 'b': 'i'}
]

output = []
for input_element in input:
    if not output:
        output.append(input_element)
    else:
        for output_element in output:
            if input_element['b'] != output_element['b']:
                output.append(input_element)

如果那是一個元組列表,解決方案會更簡單嗎,例如:

[(1, 'j'), (2, 'j'), (3, 'i')]

# to produce
[(1, 'j'), (3, 'i')]

這是一種使用any()和列表理解的方法:

代碼:

l=[
    {'a': 1, 'b': 'j'},
    {'a': 2, 'b': 'j'},
    {'a': 3, 'b': 'i'}
]

new_l = []

for d in l:
    if any([d['b'] == x['b'] for x in new_l]):
        continue
    new_l.append(d)

print(new_l)

Output:

[{'a': 1, 'b': 'j'}, {'a': 3, 'b': 'i'}]
def drop_dup_key(src, key):
    ''' src is the source list, and key is a function to obtain the key'''
    keyset, result = set(), []
    for elem in src:
        keyval = key(elem)
        if keyval not in keyset:
             result.append(elem)
             keyset.add(keyval)
    return result

像這樣使用它:

drop_dup_key(in_list, lambda d: return d.get('b'))

您可以定義一個自定義容器 class 實現__eq____hash__魔術方法。 這樣,您可以使用一set來刪除“重復項”(根據您的標准)。 這不一定保持秩序。

from itertools import starmap
from typing import NamedTuple

class MyTuple(NamedTuple):
    a: int
    b: str

    def __eq__(self, other):
        return self.b == other.b

    def __hash__(self):
        return ord(self.b)


print(set(starmap(MyTuple, [(1, 'j'), (2, 'j'), (3, 'i')])))

Output:

{MyTuple(a=3, b='i'), MyTuple(a=1, b='j')}
>>> 

我建議這個實現:

_missing = object()
def dedupe(iterable, selector=_missing):
    "De-duplicate a sequence based on a selector"
    keys = set()
    if selector is _missing: selector = lambda e: e
    for e in iterable:
        if selector(e) in keys: continue
        keys.add(selector(e))
        yield e

優點:

  • 返回一個生成器:
    它只是懶惰地迭代原始集合一次。 這在某些情況下可能有用和/或執行,特別是如果您將鏈接其他查詢操作。

     input = [{'a': 1, 'b': 'j'}, {'a': 2, 'b': 'j'}, {'a': 3, 'b': 'i'}] s = dedupe(input, lambda x: x['b']) s = map(lambda e: e['a'], s) sum(s) # Only now the list is iterated. Result: 4
  • 接受任何類型的可迭代:
    無論是列表、集合、字典還是自定義的可迭代 class。 您可以從中構造任何集合類型,而無需多次迭代。

     d = {'a': 1, 'b': 1, 'c': 2} {k: v for k, v in dedupe(d.items(), lambda e: e[1])} # Result (dict): {'a': 1, 'c': 2} {*dedupe(d.items(), lambda e: e[1])} # Result (set of tuples): {('a', 1), ('c', 2)}
  • 采用可選的選擇器 function (或任何可調用的):
    這使您可以靈活地在許多不同的上下文中以任何自定義邏輯或類型重復使用此 function。 如果選擇器不存在,它會比較整個元素。

     # de-duping based on absolute value: (*dedupe([-3, -2, -2, -1, 0, 1, 1, 2, 3, 3], abs),) # Result: (-3, -2, -1, 0) # de-duping without selector: (*dedupe([-3, -2, -2, -1, 0, 1, 1, 2, 3, 3]),) # Result: (-3, -2, -1, 0, 1, 2, 3)

元組與字典的比較不是很准確,因為元組只包含字典值,而不是鍵,我相信你在問重復的鍵:值對。

這是一個我相信可以解決您的問題的解決方案,但可能不像 pythonic 一樣。

seen = set()
kept = []

for d in x:
     keep = True
     for k, v in d.items():
         if (k, v) in seen:
             keep = False
             break
         seen.add((k, v))
     if keep:
         kept.append(d)

print(kept)

Output:

[{'a': 1, 'b': 'j'}, {'a': 3, 'b': 'i'}]

暫無
暫無

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

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