Moje pytanie jest nieco podobne do tego pytania: HTTPS: // Codereview .stackexchange.com / pytania / 175079 / usuwania -key- value - par -in- listy -of- dicts. Zasadniczo mam listę słowników i chcę usunąć duplikaty z listy na podstawie unikalnej kombinacji dwóch (lub więcej) kluczy w każdym słowniku.

Załóżmy, że mam następującą listę słowników:

some_list_of_dicts = [
{'a': 1, 'b': 1, 'c': 1, 'd': 2, 'e': 4},
{'a': 1, 'b': 1, 'c': 1, 'd': 5, 'e': 1},
{'a': 1, 'b': 1, 'c': 1, 'd': 7, 'e': 8},
{'a': 1, 'b': 1, 'c': 1, 'd': 9, 'e': 6},
{'a': 1, 'b': 1, 'c': 2, 'd': 2, 'e': 3},
{'a': 1, 'b': 1, 'c': 3, 'd': 2, 'e': 3},
{'a': 1, 'b': 1, 'c': 4, 'd': 2, 'e': 3}
]

Załóżmy, że kombinacja a, b i c musi być unikalna; Wszelkie inne wartości mogą być czymkolwiek chcą, ale połączenie tych trzech musi być unikalne dla tej listy. Chciałbym wziąć pod uwagę niezależnie od tego, który wyjątkowy kombinacja {x4}}, b i c i c

Nowa lista, po uruchomieniu go za pomocą funkcji {X0}} wyglądałaby tak:

new_list = [
{'a': 1, 'b': 1, 'c': 1, 'd': 2, 'e': 4},
{'a': 1, 'b': 1, 'c': 2, 'd': 2, 'e': 3},
{'a': 1, 'b': 1, 'c': 3, 'd': 2, 'e': 3},
{'a': 1, 'b': 1, 'c': 4, 'd': 2, 'e': 3}
]

Udało mi się tylko wymyślić:

def remove_duplicates(old_list):

    uniqueness_check_list = []
    new_list = []

    for item in old_list:
        # The unique combination is 'a', 'b', and 'c'
        uniqueness_check = "{}{}{}".format(
            item["a"], item["b"], item["c"]
        )

        if uniqueness_check not in uniqueness_check_list:
            new_list.append(item)

        uniqueness_check_list.append(uniqueness_check)

    return new_list

Ale to nie jest bardzo pytalne. Posiada również problem, że w funkcji, które klucze muszą być wyjątkowe; Byłoby lepiej, gdybym mógł określić, że jako argument do samej funkcji, ale znowu nie jestem pewien, co jest najbardziej eleganckim sposobem na to.

1
Scott Crooks 26 luty 2019, 19:43

2 odpowiedzi

Najlepsza odpowiedź

Możesz użyć dyktografii, aby skonstruować dykt z listy dyktów w odwróconej kolejności, aby wartości pierwszej z wszelkich unikalnych kombinacji miały pierwszeństwo. Użyj operator.itemgetter, aby uzyskać unikalne klucze jako krotka. Odwróć ponownie na końcu oryginalnego zamówienia:

from operator import itemgetter
list({itemgetter('a', 'b', 'c')(d): d for d in reversed(some_list_of_dicts)}.values())[::-1]

To zwraca:

[{'a': 1, 'b': 1, 'c': 1, 'd': 2, 'e': 4},
 {'a': 1, 'b': 1, 'c': 2, 'd': 2, 'e': 3},
 {'a': 1, 'b': 1, 'c': 3, 'd': 2, 'e': 3},
 {'a': 1, 'b': 1, 'c': 4, 'd': 2, 'e': 3}]
3
blhsing 26 luty 2019, 18:21

Z pomocą funkcji śledzić duplikaty, możesz użyć niektórych rozumienia listy:

def remove_duplicates(old_list, cols=('a', 'b', 'c')):
    duplicates = set()

    def is_duplicate(item):
        duplicate = item in duplicates
        duplicates.add(item)
        return duplicate

    return [x for x in old_list if not is_duplicate(tuple([x[col] for col in cols]))]

Używać:

>>> remove_duplicates(some_list_of_dicts)
[
    {'a': 1, 'c': 1, 'b': 1, 'e': 4, 'd': 2}, 
    {'a': 1, 'c': 2, 'b': 1, 'e': 3, 'd': 2}, 
    {'a': 1, 'c': 3, 'b': 1, 'e': 3, 'd': 2}, 
    {'a': 1, 'c': 4, 'b': 1, 'e': 3, 'd': 2}
]

Możesz także zapewnić różne kolumny do klucza na:

>>> remove_duplicates(some_list_of_dicts, cols=('a', 'd'))
[
    {'a': 1, 'c': 1, 'b': 1, 'e': 4, 'd': 2}, 
    {'a': 1, 'c': 1, 'b': 1, 'e': 1, 'd': 5}, 
    {'a': 1, 'c': 1, 'b': 1, 'e': 8, 'd': 7}, 
    {'a': 1, 'c': 1, 'b': 1, 'e': 6, 'd': 9}
]
1
Nikolas Stevenson-Molnar 26 luty 2019, 16:56