2013-02-13 11 views
5

Mam krotkę utworzoną z zip() i potrzebuję odjąć jedną z każdej liczby całkowitej w krotce. Próbowałem następujące, ale najwyraźniej działa tylko na listach, więc jak mam to dostosować dla krotek w Pythonie?Jak odjąć jedną z każdej wartości w kodzie w Pythonie?

[...] 
lower, upper = zip(*table) 
lower[:] = [x + 1 for x in lower] 
upper[:] = [x - 1 for x in upper] 
holes = zip(lower[:-1], upper[1:]) 

TypeError: 'tuple' object does not support item assignment

Duży obraz mam serię non-nakładających posortowanych odstępach przechowywanych w table i muszę uzyskać szereg otworów. Na przykład. mój stół interwały mogą być:

[ 6, 7] 
[ 8, 9] 
[14, 18] 
[23, 32] 

I chcę obliczyć holes pomiędzy przerwami:

[10, 13] 
[19, 22] 
+0

Po wielu wielu wnioskach, które pomogły mi @gnibbler, oraz licznych zmianach w moim kodzie, zakończyłem ostatecznie. Zobacz proszę i powiedz mi, co o tym sądzisz. – eyquem

+0

@eyquem Aby poprawić twoją odpowiedź, edytowałbym komentarz, w jaki sposób dotarłeś do odpowiedzi, aby odpowiedź była krótka i słodka. – WilliamKF

Odpowiedz

2

Korzystanie z funkcji generatora ułatwia zadanie.

table = [(2,3),(5,6),(12,20),(21,25),(28,28),(35,48),(53,55)] 

def gaps_between(intervals): 
    prec = intervals[0][1] + 1 
    for L,H in intervals: 
     print '\nprec = %d (L,H) = (%d,%d)' % (prec,L,H) 
     print 'prec = %d <= L-1 = %d : %s' % (prec,L-1,prec<=L) 
     if prec<=L-1: 
      yield (prec,L-1) 
     prec = H + 1 
     print 'next prec = %d' % prec 

holes = list(gaps_between(table)) 

print 
print 'table =',table 
print 'holes =',holes 

W poprzedniej odpowiedzi użyłem iteratora zdefiniowanego wewnątrz generatora.
Aby tego uniknąć, tutaj powyżej używam strategii:
definiowanie first prec = first H = intervals[0][1].
Biorąc pod uwagę fakt, że H>=L dla każdej pary (L, H), prowadzi to do
first H > first L - 1 ->first prec > first L - 1.
Dlatego pierwsze badanie dotyczące pierwszego przedziału jest zawsze fałszywe, a rzeczywisty proces rozpoczyna się w drugim przedziale.

prec = 3 (L,H) = (2,3) 
prec = 3 <= L-1 = 1 : False 
next prec = 4 

prec = 4 (L,H) = (5,6) 
prec = 4 <= L-1 = 4 : True 
next prec = 7 

prec = 7 (L,H) = (12,20) 
prec = 7 <= L-1 = 11 : True 
next prec = 21 

prec = 21 (L,H) = (21,25) 
prec = 21 <= L-1 = 20 : True 
next prec = 26 

prec = 26 (L,H) = (28,28) 
prec = 26 <= L-1 = 27 : True 
next prec = 29 

prec = 29 (L,H) = (35,48) 
prec = 29 <= L-1 = 34 : True 
next prec = 49 

prec = 49 (L,H) = (53,55) 
prec = 49 <= L-1 = 52 : True 
next prec = 56 

table = [(2, 3), (5, 6), (12, 20), (21, 25), (28, 28), (35, 48), (53, 55)] 
holes = [(4, 4), (7, 11), (26, 27), (29, 34), (49, 52)] 

Wynikiem jest poprawne:
- daje szczeliny (4,4) w zakresie (2-3) i (5-6)
- nie ma różnicy między (12,20) i (21,25)
- wartość 28 obecna w (28, 28) nie występuje w żadnej szczelinie

OP mówi, że odstępy nie są zachodzące na siebie i są sortowane.
Jednakże test if prec<=L-1 jest obowiązkowa, inaczej sąsiednie przedziały daje błąd:
bez tego testu, wynik będzie zawierać
....., (7, 11), (21, 20), (26, 27), .......

.

Zdarza się, że z tego obowiązkowego testu następujące wykazy odstępach
[[ 8, 9],[14, 18],[18, 32]]
[[8, 9], [14, 18], [19, 20], [16, 21], [23, 32]]
że są nadmiernie docierania (nie to, co mówi OP)
i że dałoby błąd bez testu
don W rzeczywistości nie powoduje żadnych błędów.

Reguła dla listy interwałów, aby podać poprawną listę luk za pomocą powyższego kodu, polega na tym, że przedziały muszą być posortowane wzdłuż drugiego elementu.

.

Zastąpienie yield (prec,L-1) z yield range(prec,L) spowoduje, że przerwy będą stanowiły zakresy.

Zastępując na przykład yield (prec,L-1) z holes.append((prec,L-1)), można zapisać kod bez funkcji.

+0

Przechowywanie "prec" w generatorze sprawia, że ​​rozwiązanie jest czytelne. Nie potrzebujesz klauzuli "else", po prostu przenieś 'prec = b' po bloku' if'. OP mówi teraz, że pary są sortowane i nie nakładają się, więc nie musisz testować dla tych przypadków. Ale myślę, że to prawdopodobnie ma sens, aby stłumić "puste dziury", takie jak (4, 4) i (22, 22) z wyjścia, jeśli mogą wystąpić. –

+0

Ah! masz rację dla linii '' prec = b''. Instrukcje '' a + = 1'' i '' b + = 1'' mogą być również usunięte, jeśli '' prec = b + 1''. - Ale dla (4,4) i (22, 22), to prawda: oznaczają luki tylko jednej liczby. - Wyobraziłem sobie inne rozwiązania, oparte na ouputach bezpośrednio będących zasięgiem. - Dziękuję za Twój komentarz. – eyquem

+0

Jeśli chcesz uniknąć tabeli modyfikującej, jednym ze sposobów jest po prostu ustawianie 'prec = None' na początku i testowanie go w pętli –

6

użyć konstruktora tuple z wyrażeniem prądnicy:

lower = tuple(x - 1 for x in lower) 
upper = tuple(x + 1 for x in upper) 
+0

dla uzyskania wyniku wymaganego przez OP operatory i krojenie muszą zostać zmienione w ten sposób: 'holes = zip ([x + 1 dla xw górnej] [: - 1], [x - 1 dla x w dolnej ] [1:]) ' – furins

+0

Tak, możesz to zrobić w jednym wierszu, ale myślę, że wygląda na czystsze, podzielone na wiele linii. (To tylko moja opinia). – nneonneo

+0

Przepraszam, nneonneo, że mój komentarz był związany z odesłaniem oczekiwanej odpowiedzi, a nie umieszczeniem jej w jednym wierszu (to było tylko dla łatwości, będąc tylko komentarzem). Zmodyfikowałem swój komentarz, aby wyjaśnić ten aspekt (patrz także komentarz ogzdów) – furins

6

Ty możliwe, również po prostu przetwórz je w jednym spisie ze zrozumieniem:

holes = [(table[i][1]+1, table[i+1][0]-1) for i in range(len(table)-1)] 
+0

Ah Napisałem tę samą linię, ale zapomniałem o nim, chcąc usunąć pierwszy element niższego i ostatniego elementu cholewki. myślę, że to rozwiązanie jest znacznie bardziej pythonic – placeybordeaux

+0

@ogzd, tak, że wydaje się być tym, co jest teraz pożądane jest przykład –

+0

, aby być jeszcze bardziej precyzyjnym, odpowiedź powinna brzmieć 'holes = zip ([x + 1 dla xw górnej] [ : -1], [x - 1 dla x w dolnym] [1:]) '(lista list) w celu dopasowania do podanego przykładu ...;) – furins