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'}
]
5 Réponses :
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.
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"])
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
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")
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)
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>
est-il assuré que pour les valeurs avec
rssi: 0deux 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