2013-06-15 9 views
7

Ho provato il seguente codice in Python IDLE. Ma non ho trovato gli elementi scambiati.Come utilizzare la lista [lista.index ('')] query in python

>>> a = [1,2,3,4,5,6,7] 
>>> if(a.index(2)<a.index(4)): 
...  a[a.index(2)],a[a.index(4)] = a[a.index(4)],a[a.index(2)] 

Secondo il codice, dovrebbe invertire le posizioni di 2 e 4. Correggimi Se ho torto.

risposta

12

Le espressioni della lista di assegnazione vengono valutate da sinistra a destra durante l'assegnazione di.

Ecco cosa succede:

  • La destra-espressione viene valutata per produrre (4, 2)
  • a[a.index(2)] viene valutata per assegnare 4 a, a[2] è modificato, l'elenco diventa [1, 4, 3, 4, 5, 6, 7]
  • a[a.index(4)] è valutato per assegnare 2 a, a[2] è modificato di nuovo perché ora è la prima posizione 4 è tornato a [1, 2, 3, 4, 5, 6, 7].

Si può vedere questo nel codice Python byte smontata:

>>> def foo(): 
...  a = [1,2,3,4,5,6,7] 
...  a[a.index(2)],a[a.index(4)] = a[a.index(4)],a[a.index(2)] 
... 
>>> import dis 
>>> dis.dis(foo) 
    2   0 LOAD_CONST    1 (1) 
       3 LOAD_CONST    2 (2) 
       6 LOAD_CONST    3 (3) 
       9 LOAD_CONST    4 (4) 
      12 LOAD_CONST    5 (5) 
      15 LOAD_CONST    6 (6) 
      18 LOAD_CONST    7 (7) 
      21 BUILD_LIST    7 
      24 STORE_FAST    0 (a) 

    3   27 LOAD_FAST    0 (a) 
      30 LOAD_FAST    0 (a) 
      33 LOAD_ATTR    0 (index) 
      36 LOAD_CONST    4 (4) 
      39 CALL_FUNCTION   1 
      42 BINARY_SUBSCR  
      43 LOAD_FAST    0 (a) 
      46 LOAD_FAST    0 (a) 
      49 LOAD_ATTR    0 (index) 
      52 LOAD_CONST    2 (2) 
      55 CALL_FUNCTION   1 
      58 BINARY_SUBSCR  
      59 ROT_TWO    
      60 LOAD_FAST    0 (a) 
      63 LOAD_FAST    0 (a) 
      66 LOAD_ATTR    0 (index) 
      69 LOAD_CONST    2 (2) 
      72 CALL_FUNCTION   1 
      75 STORE_SUBSCR   
      76 LOAD_FAST    0 (a) 
      79 LOAD_FAST    0 (a) 
      82 LOAD_ATTR    0 (index) 
      85 LOAD_CONST    4 (4) 
      88 CALL_FUNCTION   1 
      91 STORE_SUBSCR   
      92 LOAD_CONST    0 (None) 
      95 RETURN_VALUE   

per indice di istruzioni 59, Python ha valutato l'espressione di destra-lato; il prossimo sono i compiti. Si può vedere che a.index(2) (63-72) viene valutato per primo, quindi lo STORE_SUBSCR memorizza lo 4 e solo quindi viene valutatoa.index(4) (istruzioni 79-85).

La soluzione consiste nel chiamare .index()volta per ogni valore, e memorizzare gli indici in variabili:

index_two, index_four = a.index(2), a.index(4) 
if index_two < index_four: 
    a[index_two], a[index_four] = a[index_four], a[index_two] 
+0

Grazie per la risposta! Quindi come faccio a scambiare 2 e 4 in elenco se posso accedere solo ai suoi valori di indice? –

1

Per evitare questo, è possibile memorizzare il risultato delle .index() chiamate nelle variabili, poi fare lo scambio con loro:

>>> a = [1,2,3,4,5,6,7] 
>>> i2 = a.index(2) 
>>> i4 = a.index(4) 
>>> if i2<i4: 
...  a[i2], a[i4] = a[i4], a[i2] 
>>> a 
[1, 4, 3, 2, 5, 6, 7] 

In questo modo si evita anche di chiamare quel metodo tre volte quando una volta è sufficiente.

5

La risposta di Martijn è completa e spiega il problema che si sta verificando. Se si sta ancora chiedendo come scrivere il codice che fa quello che si vuole, provare qualcosa di simile:

if (a.index(2) < a.index(4)): 
    x,y = a.index(4),a.index(2) 
    a[x],a[y] = a[y],a[x] 

L'idea qui è fondamentalmente solo per memorizzare i valori di ritorno index in qualcosa al di fuori della lista stessa. Salvando gli indici separatamente in questo modo si evita la condizione di gara che si stava avendo.

+0

Questo ancora chiama '.index()' due volte troppo spesso per i miei gusti :) –

+0

Sto mirando alla chiarezza per brevità. :) – theJollySin

+0

Abbastanza soddisfacente :) +1 –

Problemi correlati