2016-02-28 21 views
5

ho un oggetto che è una lista di liste di dizionari:ordinamento di un elenco di liste di dizionari in python

myObject =[[{ "play": 5.00, "id": 1, "uid": "abc" }, \ 
      { "play": 1.00, "id": 2, "uid": "def" }], \ 
      [{ "play": 6.00, "id": 3, "uid": "ghi" }, \ 
      { "play": 7.00, "id": 4, "uid": "jkl" }], \ 
      [{ "play": 3.00, "id": 5, "uid": "mno" }, \ 
      { "play": 1.00, "id": 6, "uid": "pqr" }]] 

voglio ordinare l'elenco per la somma dei play valori nei dizionari di ogni annidato elenco. L'oggetto sarebbe quindi essere ordinata in questo modo:

myObject =[[{ "play": 6.00, "id": 3, "uid": "ghi" }, \ 
      { "play": 7.00, "id": 4, "uid": "jkl" }], \ 
      [{ "play": 5.00, "id": 1, "uid": "abc" }, \ 
      { "play": 1.00, "id": 2, "uid": "def" }], \ 
      [{ "play": 3.00, "id": 5, "uid": "mno" }, \ 
      { "play": 1.00, "id": 6, "uid": "pqr" }]] 

Se fosse solo un elenco di dicts poi:

sorted(myObject, key=sum(map(itemgetter(play))), reverse=True)

avrebbe funzionato. Non riesco a capire come farlo senza dover scorrere l'elenco, calcolare la somma, quindi ordinare. Questo è quello che sto facendo ora, ma sto cercando di aumentare l'efficienza di questo codice rimuovendo i loop perché il mio elenco contiene centinaia di milioni di liste.

+2

Proprio come una nota: in questo caso non sono necessarie le continuazioni di riga '' \ ''. Poiché le righe terminano con una virgola e i letterali delle liste sono ancora "aperti", Python si aspetta automaticamente che la riga successiva continui lì. – poke

risposta

4

La tua idea è già molto buono, per usare una funzione chiave personalizzata durante l'ordinamento e l'utilizzo sum, map e un itemgetter sul tasto play:

key=sum(map(itemgetter(play))) 

Si ha un problema qui però: L'argomento key si aspetta una funzione che prende un elemento del tuo elenco che stai ordinando. Ma né summap restituiscono una funzione, quindi non è possibile utilizzarla come funzione chiave. Invece, potresti eseguire una funzione lambda che esegue questa combinazione per ciascun elemento.

Gli altri problemi sono che play deve essere una stringa 'play' invece che map dovrebbe richiedere la sottolista come argomento. Quindi la tua funzione chiave sarebbe la seguente:

key=lambda x: sum(map(itemgetter('play'), x)) 

Questo è tutto. funzionalmente equivalente alla seguente comprensione generatore che potrebbe essere più leggibile:

key=lambda x: sum(y['play'] for y in x) 

Utilizzando questo con sorted dovrebbe funzionare, ma si dovrebbe prendere in considerazione l'ordinamento vostra lista direttamente utilizzando list.sort invece:.

>>> myObject = [[{ "play": 5.00, "id": 1, "uid": "abc" }, 
       { "play": 1.00, "id": 2, "uid": "def" }], 
       [{ "play": 6.00, "id": 3, "uid": "ghi" }, 
       { "play": 7.00, "id": 4, "uid": "jkl" }], 
       [{ "play": 3.00, "id": 5, "uid": "mno" }, 
       { "play": 1.00, "id": 6, "uid": "pqr" }]] 

>>> myObject.sort(key=lambda x: sum(y['play'] for y in x), reverse=True) 

>>> for x in myObject: 
     print(x) 

[{'play': 6.0, 'uid': 'ghi', 'id': 3}, {'play': 7.0, 'uid': 'jkl', 'id': 4}] 
[{'play': 5.0, 'uid': 'abc', 'id': 1}, {'play': 1.0, 'uid': 'def', 'id': 2}] 
[{'play': 3.0, 'uid': 'mno', 'id': 5}, {'play': 1.0, 'uid': 'pqr', 'id': 6}] 

(Btw myObject è tipo di brutto nome per un elenco di cose.)


Per quanto riguarda l'efficienza o la complessità del tuo problema va, davvero non si può evitare di dover passare attraverso ogni sottolista alla fine. È impossibile determinare la somma di questi valori senza guardare i valori, quindi ovviamente non è possibile evitarlo.

Tuttavia, è necessario assicurarsi che ogni somma venga calcolata una sola volta, per evitare di dover guardare gli articoli nelle sottoliste più di una volta. Fortunatamente, il difetto ordinamento utilizzando list.sort non esattamente garantire che:

Il tasto corrispondente a ciascun elemento nell'elenco calcolato una sola volta e poi utilizzato per l'intero processo di sequenziazione.

Quindi si avrà una soluzione molto efficiente per questo problema di ordinamento.

+0

Non dovrebbe essere 'reverse = True' per ottenere il massimo prima –

+0

@PaulRooney Oh sì, ho perso quel dettaglio nella domanda (anche se non è veramente rilevante per il problema di classificazione). Grazie! – poke