Domanda

È un problema interessante che cerca la soluzione più Pythonic. Supponiamo di avere un elenco di mappature {'id': id, 'url': url} . Alcuni id nell'elenco sono duplicati e desidero creare un nuovo elenco, con tutti i duplicati rimossi. Mi è venuta in mente la seguente funzione:

def unique_mapping(map):
    d = {}
    for res in map:
        d[res['id']] = res['url']

    return [{'id': id, 'url': d[id]} for id in d]

Suppongo sia abbastanza efficiente. Ma c'è un "più Pythonic" modo ? O forse un modo più efficiente?

È stato utile?

Soluzione

Il tuo esempio può essere riscritto leggermente per costruire il primo dizionario usando un'espressione di generatore e per rimuovere la necessità di costruzione di un'altra mappatura. Riutilizza solo quelli vecchi:

def unique_mapping(mappings):
    return dict((m['id'], m) for m in mappings).values()

Anche se questo è uscito come one-liner, penso ancora che sia abbastanza leggibile.

Ci sono due cose che devi tenere a mente quando usi la tua soluzione originale e la mia:

  • gli articoli non saranno sempre restituiti nello stesso ordine in cui erano originariamente
  • la voce successiva sovrascriverà le voci precedenti con lo stesso ID

Se non ti dispiace, allora suggerisco la soluzione sopra. In altri casi, questa funzione preserva l'ordine e tratta gli ID incontrati per primi con priorità:

def unique_mapping(mappings):
    addedIds = set()
    for m in mappings:
        mId = m['id']
        if mId not in addedIds:
            addedIds.add(mId)
            yield m

Potrebbe essere necessario chiamarlo con list (unique_mappings (mapping)) se hai bisogno di un elenco e non di un generatore.

Altri suggerimenti

Ci sono un paio di cose che potresti migliorare.

  • Stai eseguendo due loop, uno sul dict originale e poi di nuovo sul dict risultante. Invece, potresti creare i tuoi risultati in un solo passaggio.

  • Potresti cambiare per usare un generatore, per evitare di costruire l'intero elenco in anticipo. (Usa list (unique_mapping (items)) per convertire in un elenco completo se ne hai bisogno)

  • Non è necessario archiviare il valore quando si verifica solo la presenza di duplicati, è possibile utilizzare un set.

  • Stai ricreando un dizionario per ciascun elemento, anziché restituire l'originale. Questo potrebbe effettivamente essere necessario (ad es. Li stai modificando e non vuoi toccare l'originale), ma in caso contrario, è più efficiente usare i dizionari già creati.

Ecco un'implementazione:

def unique_mapping(items):
    s = set()
    for res in items:
        if res['id'] not in s:
            yield res
            s.add(res['id'])

Penso che questo possa essere reso ancora più semplice. I dizionari non tollerano chiavi duplicate. Trasforma il tuo elenco di mappature in un dizionario di mappature. Ciò rimuoverà i duplicati.

>>> someListOfDicts= [
    {'url': 'http://a', 'id': 'a'}, 
    {'url': 'http://b', 'id': 'b'}, 
    {'url': 'http://c', 'id': 'a'}]

>>> dict( [(x['id'],x) for x in someListOfDicts ] ).values()

[{'url': 'http://c', 'id': 'a'}, {'url': 'http://b', 'id': 'b'}]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top