1
votes

Python - supprime l'élément en double de la liste des dictionnaires en fonction de la valeur du dictionnaire

J'ai une liste de dictionnaires qui ont des identifiants en double et j'aimerais conserver les dictionnaires qui ont une valeur sous rsrp et supprimer ceux qui ont 0, mais s'il y a un doublon qui a rsrp de 0 en deux fois Je dois le garder.

Les exemples de liste actuels et souhaités sont ci-dessous, y a-t-il un moyen simple de le faire? trouver non '0' avec une boucle est le plus facile mais si les identifiants correspondants sont '0' je ne suis pas sûr

current_list = [
    {'id': 255, 'rssi': -108.0},
    {'id': 255, 'rssi': '0'},
    {'id': 301, 'rssi': -82.0},
    {'id': 301, 'rssi': '0'},
    {'id': 263, 'rssi': -85.0},
    {'id': 263, 'rssi': '0'},
    {'id': 18, 'rssi': '0'},
    {'id': 18, 'rssi': '0'}
]

desired_list = [
    {'id': 255, 'rssi': -108.0},
    {'id': 301, 'rssi': -82.0},
    {'id': 263, 'rssi': -85.0},
    {'id': 18, 'rssi': '0'}
]


2 commentaires

est-il assuré que pour les valeurs avec rssi: 0 deux fois, nous n'aurons pas également un rssi non nul avec le même identifiant? De plus, est-il assuré qu'un identifiant n'aura qu'au plus 1 rssi non nul? Essentiellement, y a-t-il des cas où la logique peut échouer?


il pourrait y avoir un identifiant sans aucune valeur nulle, je ne l'ai pas encore vu mais il pourrait aussi y avoir trois zéros et un avec une valeur


5 Réponses :


3
votes

dans les recettes itertools , il existe une méthode appelée unique_everseen:

desired_list = list(unique_everseen(current_list, key=lambda x: x["rssi"]))
# [{'id': 255, 'rssi': -108.0}, {'id': 255, 'rssi': '0'}, 
#  {'id': 301, 'rssi': -82.0}, {'id': 263, 'rssi': -85.0}]

vous pouvez l'utiliser pour obtenir la liste souhaitée:

from itertools import filterfalse

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

tout ce qui reste à sélectionnez 'rssi' en utilisant le paramètre key de unique_everseen.


0 commentaires

2
votes

En utilisant une itération simple.

Ex:

[{'id': 255, 'rssi': -108.0},
 {'id': 301, 'rssi': -82.0},
 {'id': 263, 'rssi': -85.0},
 {'id': 18, 'rssi': '0'}]

Sortie:

current_list = [
    {'id': 255, 'rssi': -108.0},
    {'id': 255, 'rssi': '0'},
    {'id': 301, 'rssi': -82.0},
    {'id': 301, 'rssi': '0'},
    {'id': 263, 'rssi': -85.0},
    {'id': 263, 'rssi': '0'},
    {'id': 18, 'rssi': '0'},
    {'id': 18, 'rssi': '0'}
]
seen = set()
result = []
for i in sorted(current_list, key=lambda x: True if x["rssi"] == "0" else False):
    if (i["id"] not in seen and i["rssi"] != "0") or \
            (i["id"] not in seen and i["rssi"] == "0"):
        result.append(i)
        seen.add(i["id"])


2 commentaires

Cela suppose que les identifiants en double arrivent de manière séquentielle. rssi! = 0 toujours avant rssi = 0. Que faire s'ils sont dans l'ordre inverse? `current_list = [{'id': 255, 'rssi': '0'}, {'id': 255, 'rssi': -108.0}]` Cela ne semble plus fonctionner.


@Miles Davis. Merci de ne pas voir ce cas. Extrait mis à jour



0
votes

Si vous pouvez utiliser des bibliothèques externes dans votre projet, vous pouvez tirer parti des opérations vectorisées Pandas.

Par exemple. :

import pandas as pd

df = pd.DataFrame(current_list)
df["rssi"] = pd.to_numeric(df["rssi"])
df = df[(df["rssi"] != 0) | (df.groupby("id").transform("min") == 0)["rssi"]]
df = df.drop_duplicates()
df.to_dict("records")


0 commentaires

0
votes

Une solution utilisant itertools.groupby . S'il y a un élément avec rssi seulement 0 , nous en gardons un. Nous ajoutons tous les autres éléments rssi non nuls à la liste de sortie:

[{'id': 18, 'rssi': '0'},
 {'id': 255, 'rssi': -108.0},
 {'id': 263, 'rssi': -85.0},
 {'id': 301, 'rssi': -82.0}]

Impressions:

current_list = [
    {'id': 255, 'rssi': -108.0},
    {'id': 255, 'rssi': '0'},
    {'id': 301, 'rssi': -82.0},
    {'id': 301, 'rssi': '0'},
    {'id': 263, 'rssi': -85.0},
    {'id': 263, 'rssi': '0'},
    {'id': 18, 'rssi': '0'},
    {'id': 18, 'rssi': '0'}
]

from itertools import groupby

out = []
for v, g in groupby(sorted(current_list, key=lambda k: (k['id'], k['rssi'] == '0')), lambda k: k['id']):
    out.append(next(g)) # ensure we add at least one `0`
    out.extend(i for i in g if i['rssi'] != '0')  # add any non-zero `rssi` items


from pprint import pprint
pprint(out)


0 commentaires

0
votes

Sans utiliser de import s, je le ferais de la manière suivante:

[{'id': 255, 'rssi': -108.0}, {'id': 301, 'rssi': -82.0}, {'id': 263, 'rssi': -85.0}, {'id': 18, 'rssi': '0'}]

Sortie:

current_list = [
    {'id': 255, 'rssi': -108.0},
    {'id': 255, 'rssi': '0'},
    {'id': 301, 'rssi': -82.0},
    {'id': 301, 'rssi': '0'},
    {'id': 263, 'rssi': -85.0},
    {'id': 263, 'rssi': '0'},
    {'id': 18, 'rssi': '0'},
    {'id': 18, 'rssi': '0'}
]
output = {}
for i in current_list:
    if not i['id'] in output:
        output[i['id']] = []
    output[i['id']].append(i['rssi'])
# now output is {255: [-108.0, '0'], 301: [-82.0, '0'], 263: [-85.0, '0'], 18: ['0', '0']}
def func(x):
    for j in x:
        if j!='0':
            return j
    return '0'
desired_list = [{'id':i[0],'rssi':func(i[1])} for i in output.items()]
print(desired_list)

p>


0 commentaires