2010-11-02 13 views
5

Ich schrieb diese Klasse zum Komprimieren und Erweitern von Zahlenlisten zu Sequenzstrings, einschließlich Schrittwerte, wenn der Schrittwert größer als 1 ist. Der Code fühlt sich immer noch klobig an. Gibt es Bibliotheken, die so etwas tun können? Möglicherweise einfacherer Code?Drucken eines formatierten numerischen Bereichs Zeichenfolgen aus einer Liste von Zahlen in Python

import re 

class Foo(object): 

    def __init__(self, num_list): 
     self.num_list = sorted(list(set([ int(n) for n in num_list ]))) 
    # end def __init__ 

    def gen_seq_data(self): 
     self.seq_data  = list() 
     index_offset  = None 
     backward_step_value = None 
     forward_step_value = None 
     sub_list   = list() 
     sub_list_step_value = None 
     for index, num in enumerate(self.num_list): 

      if index - 1 < 0: 
       backward_step_value = None 
      # end if 
      else: 
       backward_step_value = num - self.num_list[ index - 1 ] 
      # end else 

      try: 
       forward_step_value = self.num_list[ index + 1 ] - num 
      # end try 
      except IndexError: 
       forward_step_value = None 
      # end except 

      if backward_step_value is None: 
       sub_list.append(num) 
      # end if 
      elif backward_step_value == forward_step_value: 
       sub_list.append(num) 
       if forward_step_value is None: 
        self.seq_data.append((sub_list_step_value, sub_list)) 
       # end if 
      # end if 
      elif backward_step_value == sub_list_step_value: 
       sub_list.append(num) 
       if sub_list: 
        self.seq_data.append((sub_list_step_value, sub_list)) 
       # end if 
       sub_list = list() 
      # end elif 
      else: 
       if sub_list: 
        self.seq_data.append((sub_list_step_value, sub_list)) 
       # end if 
       sub_list = [ num ] 
       if forward_step_value is None: 
        self.seq_data.append((sub_list_step_value, sub_list)) 
       # end if 
      # end else 

      try: 
       sub_list_step_value = sub_list[ -1 ] - sub_list[ -2 ] 
      # end try 
      except IndexError: 
       sub_list_step_value = None 
      # end except 
     # end for 
    # end def gen_seq_object 

    def format_elements(self): 
     format_elements = list() 
     for step, num_list in self.seq_data: 
      if step is None: 
       format_elements.append('%s' % (num_list[ 0 ])) 
      # end if 
      elif step == 1: 
       format_elements.append('%s-%s' % (num_list[ 0 ], num_list[ -1 ])) 
      # end elif 
      else: 
       format_elements.append('%s-%sx%s' % (num_list[ 0 ], num_list[ -1 ], step)) 
      # end else 
     # end for 
     return format_elements 
    # end def format_range 

    def format_range(self): 
     return ','.join(self.format_elements()) 
    # end def format_range 

    def expand_range(self): 
     num_list = list() 
     for r_token in self.format_range().split(','): 
      if r_token.isdigit(): 
       num_list.append(int(r_token)) 
      # end if 
      elif '-' in r_token: 
       if 'x' in r_token: 
        start, end, step = re.split(r'[-|x]', r_token) 
        num_list.extend(range(int(start), int(end) + 1, int(step))) 
       # end if 
       else: 
        start, end = r_token.split('-') 
        num_list.extend(range(int(start), int(end) + 1)) 
       # end else 
      # end elif 
     # end for 
     return num_list 
    # end def expand_range 

# end class Foo 

Eingang/Ausgang:

data = [ 1, 4, 5, 6, 10, 15, 16, 17, 18, 20, 22, 24, 26, 27, 28, 30, 35, 40, 45, 50, 56, 63, 66, 69, 72 ] 

foo = Foo(data) 
foo.gen_seq_data() 

print data 

print foo.format_range() 
1,4-6,10,15-18,20-26x2,27,28,30-50x5,56,63-72x3 

print foo.expand_range() 
[1, 4, 5, 6, 10, 15, 16, 17, 18, 20, 22, 24, 26, 27, 28, 30, 35, 40, 45, 50, 56, 63, 66, 69, 72] 
+0

Bitte beheben Sie Ihre Einrückung. Ihr Code ist falsch formatiert. Bitte (1) bearbeite die Frage, (2) lies die Formatierungsanweisungen auf der rechten Seite und (3) vermeide es, jedes Stück Code, das du besitzt, zu veröffentlichen. Welches Problem hast du? Was ist der kleinste Code, der dieses ** Problem ** zeigt? –

+3

@ user494203: Wegwerfen "# end if" usw. Zeilen; sie sind ungeheuer nutzlos, besonders diejenigen, die kurz vor elif und sonst el auftreten. Wenn Sie das tun, neigen die Leute eher dazu, Ihren Code zu lesen und weitere Unauffälligkeiten vorzuschlagen. –

Antwort

2

One. Entferne alle # END Kommentare. Sie sind ungeheuer nutzlos. Ihre Einrückung spricht für sich. Benutze es.

Zwei. Mach das nicht zu einer Klasse. Es ist kein eindeutiges Objekt mit unterschiedlichen Verantwortlichkeiten. Es ist nur ein Algorithmus. Besteht aus Funktionen. Im besten Fall ist es eine Klasse mit allen statischen Methoden.

Drei. Nie tun dies

for index, num in enumerate(self.num_list): 
     if index - 1 < 0: 
      backward_step_value = None 
     # end if 
     else: 
      backward_step_value = num - self.num_list[ index - 1 ] 
     # end else 

Wenn das erste Element speziell ist, es dann separat behandeln.

backward_step_value = self.num_list[0] 
for num in self.num_list[1:]: 

Sie brauchen selten den Index für so etwas. In der Tat scheint der einzige Grund dafür zu sein, das erste Element speziell zu behandeln.

Schließlich ist dies eine "Reduktion". Verwenden Sie eine Generatorfunktion

Das könnte Ihre Liste der zusammenhängenden Bereiche ergeben. Sie können diese dann formatieren.

format_elements(reduce_list(some_list)) 
+0

Diese Lösung erreicht nicht den schwierigsten Teil der OP-Lösung, nämlich nicht nur kontinuierliche Bereiche zu identifizieren, sondern Bereiche mit einem festen Schritt> 1. – jchl

+0

@jchl: Richtig. Der Punkt war nicht, ihren Code zu reparieren. Es ging darum, den Code so zu überarbeiten, dass er weniger "klobig" ist. Das Hinzufügen des Schritts als eine Variable anstelle von "1" sollte nicht zu schwierig sein, um dies zu erweitern. –

1

Die folgende Lösung Griffe nicht zusammenhängende Bereiche, und bewahrt auch das Verhalten von Bereichen von Länge zu ignorieren 2.

def reduce_list(seq): 
    l = sorted(set(seq)) 
    low = high = l[0] 
    step = None 
    for v in l[1:]: 
     if step is None or v - high == step: 
      # Extend the current range. 
      step = v - high 
      high = v 
     elif high - low == step: 
      # The current range only has two values. Yield the 
      # first value, and start a new range comprising the 
      # second value and the current value. 
      yield low, low, None 
      step = v - high 
      low = high 
      high = v 
     else: 
      # Yield the current range, and start a new one. 
      yield low, high, step 
      low = high = v 
      step = None 
    if high - low == step: 
     # The final range has only two values. Yield them 
     # individually. 
     yield low, low, None 
     step = None 
     low = high 
    yield low, high, step 

def format_element(low, high, step): 
    if step is None: 
     assert low == high 
     return "%s" % (low,) 
    elif step == 1: 
     return "%s-%s" % (low, high) 
    else: 
     return "%s-%sx%s" % (low, high, step) 

def format_list(seq): 
    return ','.join(format_element(*e) for e in seq) 

Hier einige Testcode:

def test(*args): 
    print args, "==", format_list(reduce_list(args)) 

test(1) 
test(1, 2) 
test(1, 2, 3) 
test(0, 10) 
test(0, 10, 20) 
test(0, 10, 11, 12, 14, 16) 
test(0, 2, 4, 8, 16, 32, 64) 
test(0, 1, 3, 4, 6, 7, 9, 10) 
test(0, 1, 3, 6, 10, 15, 21, 28) 

die Ausgänge:

(1,) == 1 
(1, 2) == 1,2 
(1, 2, 3) == 1-3 
(0, 10) == 0,10 
(0, 10, 20) == 0-20x10 
(0, 10, 11, 12, 14, 16) == 0,10-12,14,16 
(0, 2, 4, 8, 16, 32, 64) == 0-4x2,8,16,32,64 
(0, 1, 3, 4, 6, 7, 9, 10) == 0,1,3,4,6,7,9,10 
(0, 1, 3, 6, 10, 15, 21, 28) == 0,1,3,6,10,15,21,28 
+0

Danke für Ihre Hilfe. Dies sind großartige Lösungen. – Bip

Verwandte Themen