2016-01-10 24 views
6

Se volevo un elenco da 0 a 100 in incrementi di cinque, potrei usare range(0,105,5), ma potrei anche usare range(0,101,5).Modalità pitonica per utilizzare l'intervallo con l'ultimo numero escluso?

Onestamente, nessuno di questi ha senso per me perché escludere l'ultimo numero sembra non intuitivo.

A parte questo, qual è il modo "corretto" per creare un elenco da 0 a 100 in intervalli di cinque? E se qualcuno ha il tempo, in quale caso, escludendo l'ultimo numero, è più facile leggere il codice?

+4

Questa è la vecchia roba CS: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html – thebjorn

risposta

8

Le due scelte elencate non sono simili. Uno è range(start, stop+step, step) e l'altro è range(start, stop+1, step). Non è necessario restituire la stessa cosa. L'unico caso che fanno è quando stop - start è divisibile per step.

>>> start, stop, step = 0, 42, 5 
>>> range(start, stop+step, step) 
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45] 
>>> range(start, stop+1, step) 
[0, 5, 10, 15, 20, 25, 30, 35, 40] 

Quindi, quale si dovrebbe usare?Se si desidera [start, stop] (incluso), quindi utilizzare stop+1 per la fine dell'intervallo. Qualcosa di più di stop+1 avrà effetti collaterali come sopra. range(0, 42+5, 5) include 45 come risultato, che non è compreso nell'intervallo [0, 42]. Come ti senti a riguardo?

1

La funzione range funziona così:

i = lowerBound 
while True: 
    if(i < upperBound): 
     range_list.append(i) 
     i += step 
    else: 
     break 

Questo è il motivo per cui range(0, 105, 5) == range(0, 101, 5)

e il modo corretto per escludere upper bound:

range(lowerBound, upperBound+step, step) 

Da Python doc:

Il modulo completo restituisce un elenco di interi semplici [start, start + step, start + 2 * step, ...].

1

Il modo corretto per creare una lista da 0 a 100 in passi di cinque è

range(0, 100, 5) 

questa lista ha 100/5 == 20 elementi e non include il numero 100.

Dijkstra ha spiegato il motivo per cui il conteggio deve iniziare da zero e gli intervalli dovrebbe essere semiaperta un (molto?) Tempo fa: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

Dal gamma di Python segue Dijkstra e usa intervalli semiaperti, ne consegue che per creare uno oltre la metà intervallo aperto è necessario aggiungere uno:

range(0, 100+1, 5) # closed interval [0..100] by five 

e, sì, mi aspetto di vederlo scritto esattamente come quello in codice di produzione dal momento che è insolito.

+0

Ma lui vuole [0,100] non [0,100). – jarmod

+0

@jarmod probabilmente non lo fa (di solito è un bug), ma ho incluso come può ottenerlo. – thebjorn

1

In pratica si potrebbe definire la funzione gamma con incluso il valore superiore e poi utilizzarlo nel codice:

def range_with_stop(start, stop, step): 
    return range(start, stop + step, step) 

In [201]: print(list(range_with_end(0, 100, 5))) 
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] 

EDIT

Secondo l'@ Reti43 rispondete si potrebbe cambiare quella funzione a seguendo (perché penso che per quel caso come @ Reti43 menzionato vuoi range (0, 40, 5) restituito):

def range_with_stop(start, stop, step): 
    if stop//step == 0: 
     return(range(start, stop + step, step)) 
    else: 
     return(range(start, step * (stop//step), step)) 

In [265]: range_with_stop(start, 42, step) 
Out[265]: range(0, 40, 5) 

In [266]: range_with_stop(start, 45, step) 
Out[266]: range(0, 45, 5) 
1

Se si desidera essere in grado di calcolare la dimensione della sequenza in base ai parametri alla chiamata della funzione range(), è necessario utilizzare range(0,105,5). Si consideri il seguente:

len(range(0,6,1)) == 6 == 6/1

len(range(0,6,2)) == 3 == 6/2

len(range(0,6,3)) == 2 == 6/3

len(range(0,6,4)) == 1 == floor(6/4)

Con questo modo, si avrebbe

len(range(0,105,5)) == 21 == 105/5