2015-08-25 6 views
6

ingresso:Come dividere un elenco ordinato in liste sub quando due differenza di valore vicini è più grande di una soglia

  • un sorted list, come questo: [1,2,3,8,10,15,16,17,18,22,23,27,30,31]
  • una soglia, come questo: max_diff = 2

risultato atteso:

  • una lista di liste sub; ciascuna lista sotto contiene i valori che la differenza vicini è più piccolo di max_diff, in questo modo: [[1, 2, 3], [8, 10], [15, 16, 17, 18], [22, 23], [27], [30, 31]]

Ecco come ho fatto questo, mi chiedo se c'è un modo migliore per farlo.

test_list = [1,2,3,8,10,15,16,17,18,22,23,27,30,31] 
max_diff = 2 

splited_list = [] 
temp_list = [test_list[0]] 
for i in xrange(1,len(test_list)): 
    if test_list[i] - temp_list[-1] > max_diff: 
     splited_list.append(temp_list) 
     temp_list = [test_list[i]] 
    else: 
     temp_list.append(test_list[i])   
    if i == len(test_list) -1: 
     splited_list.append(temp_list) 

print splited_list 
+0

recensione Codice http://codereview.stackexchange.com/ – Praveen

+0

Se questo codice è completamente funzionante e vi piacerebbe solo migliorare su di essa, si potrebbe essere meglio la pubblicazione sul CodeReview come Suggerì Praveen. Ma assicuratevi di leggere la loro pagina [Come chiedere] (http://codereview.stackexchange.com/help/how-to-ask). – SuperBiasedMan

risposta

2

È possibile utilizzare enumerate e zip funzione all'interno di una lista di comprensione per trovare gli indici degli elementi che differenza valore è maggiore di 2, quindi dividere la lista in base a lista degli indici:

>>> li =[1, 2, 3, 8, 10, 15, 16, 17, 18, 22, 23, 27, 30, 31] 
>>> inds=[0]+[ind for ind,(i,j) in enumerate(zip(li,li[1:]),1) if j-i>2]+[len(li)+1] 
>>> [li[i:j] for i,j in zip(inds,inds[1:])] 
[[1, 2, 3], [8, 10], [15, 16, 17, 18], [22, 23], [27], [30, 31]] 
0
>>> a = [1,2,3,8,10,15,16,17,18,22,23,27,30,31] 
>>> b = a[1:] #offset by 1 position 
>>> b 
[2, 3, 8, 10, 15, 16, 17, 18, 22, 23, 27, 30, 31] 
>>> c = [(i[1] - i[0]) for i in zip(a[:-1], b)] 
>>> c #position diff 
[1, 1, 5, 2, 5, 1, 1, 1, 4, 1, 4, 3, 1] 
>>> d = [i[0] for i in enumerate(c) if i[1] > 2] 
>>> d #split position 
[2, 4, 8, 10, 11] 
>>> e = [-1]+d+[len(a)] 
>>> e #add start end to split position 
[-1, 2, 4, 8, 10, 11, 14] 
>>> [a[l[0]+1: l[1]+1] for l in zip(e, e[1:])] 
[[1, 2, 3], [8, 10], [15, 16, 17, 18], [22, 23], [27], [30, 31]] 
#split result 
0

Riorganizzare le linee conduce ad una forma più compatta:

test_list = [1,2,3,8,10,15,16,17,18,22,23,27,30,31] 
max_diff = 2 

splited_list = [] 
prev_element = float('-inf') 
for element in test_list: 
    if element - prev_element > max_diff: 
     splited_list.append([]) 
    splited_list[-1].append(element) 
    prev_element = element 
print splited_list 
0

Funziona su tutti i iterables

def split_by_threshold(seq, max_diff=2): 
    it = iter(seq) 
    last = next(it) 
    part = [last] 

    for curr in it: 
     if curr - last > max_diff: 
      yield part 
      part = [] 

     part.append(curr) 
     last = curr 

    yield part 


l = [1,2,3,8,10,15,16,17,18,22,23,27,30,31] 
print(list(split_by_threshold(l))) 
+0

perché non usi un ciclo for? – Daniel

+0

Hai ragione, non mi è venuto in mente che sto effettivamente costruendo un ciclo for. – pacholik

+0

Fondamentalmente la soluzione che stavo per pubblicare, e l'ho praticamente finita, ma ero così stanco che non l'ho ultimato _ completamente: P. – Cyphase

Problemi correlati