Ich habe eine Liste mit Daten als solchen:
[1, 2, 3, 4, 7, 8, 10, 11, 12, 13, 14]
Ich möchte die Bereiche aufeinander folgender ganzer Zahlen ausdrucken:
1-4, 7-8, 10-14
Gibt es eine integrierte/schnelle/effiziente Möglichkeit, dies zu tun?
Von den Dokumenten :
>>> from itertools import groupby
>>> from operator import itemgetter
>>> data = [ 1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
>>> for k, g in groupby(enumerate(data), lambda (i, x): i-x):
... print map(itemgetter(1), g)
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]
Sie können dies ziemlich leicht anpassen, um einen gedruckten Satz von Bereichen zu erhalten.
Built-In: Nein, soweit ich weiß.
Sie müssen das Array durchlaufen. Beginnen Sie mit dem Einfügen des ersten Werts in eine Variable und drucken Sie ihn aus. Solange Sie die nächste Zahl drücken, müssen Sie sich nur die letzte Zahl in einer anderen Variable merken. Wenn die nächste Nummer nicht in einer Reihe steht, überprüfen Sie die zuletzt gespeicherte Nummer gegenüber der ersten Nummer. Wenn es das gleiche ist, tu nichts. Wenn es anders ist, drucken Sie "-" und die letzte Zahl. Geben Sie dann den aktuellen Wert in die erste Variable ein und beginnen Sie von vorne. Am Ende des Arrays führen Sie dieselbe Routine aus, als hätten Sie eine Zahl außerhalb der Zeile getroffen.
Ich hätte den Code natürlich schreiben können, aber ich möchte Ihre Hausaufgaben nicht verderben :-)
Dies wird genau so gedruckt, wie Sie es angegeben haben:
>>> nums = [1, 2, 3, 4, 7, 8, 10, 11, 12, 13, 14]
>>> ranges = sum((list(t) for t in Zip(nums, nums[1:]) if t[0]+1 != t[1]), [])
>>> iranges = iter(nums[0:1] + ranges + nums[-1:])
>>> print ', '.join([str(n) + '-' + str(next(iranges)) for n in iranges])
1-4, 7-8, 10-14
Wenn die Liste einzelne Nummernbereiche hat, werden diese als n-n angezeigt:
>>> nums = [1, 2, 3, 4, 5, 7, 8, 9, 12, 15, 16, 17, 18]
>>> ranges = sum((list(t) for t in Zip(nums, nums[1:]) if t[0]+1 != t[1]), [])
>>> iranges = iter(nums[0:1] + ranges + nums[-1:])
>>> print ', '.join([str(n) + '-' + str(next(iranges)) for n in iranges])
1-5, 7-9, 12-12, 15-18
Eine kurze Lösung, die ohne zusätzliche Importe funktioniert. Es akzeptiert alle Iterationen, sortiert unsortierte Eingaben und entfernt doppelte Elemente:
def ranges(nums):
nums = sorted(set(nums))
gaps = [[s, e] for s, e in Zip(nums, nums[1:]) if s+1 < e]
edges = iter(nums[:1] + sum(gaps, []) + nums[-1:])
return list(Zip(edges, edges))
Beispiel:
>>> ranges([2, 3, 4, 7, 8, 9, 15])
[(2, 4), (7, 9), (15, 15)]
>>> ranges([-1, 0, 1, 2, 3, 12, 13, 15, 100])
[(-1, 3), (12, 13), (15, 15), (100, 100)]
>>> ranges(range(100))
[(0, 99)]
>>> ranges([0])
[(0, 0)]
>>> ranges([])
[]
Dies ist das Gleiche wie @ dansalmo's Lösung , die ich erstaunlich fand, wenn auch etwas schwer zu lesen und anzuwenden (da sie nicht als Funktion angegeben ist).
Man beachte, dass er leicht modifiziert werden kann, um "herkömmliche" offene Bereiche [start, end)
auszuspucken, z. die return-Anweisung ändern:
return [(s, e+1) for s, e in Zip(edges, edges)]
Hier ist eine weitere grundlegende Lösung ohne Verwendung eines Moduls, die sich für ein Interview eignet. In der Regel wird das Interview ohne Module verwendet:
#!/usr/bin/python
def split_list(n):
"""will return the list index"""
return [(x+1) for x,y in Zip(n, n[1:]) if y-x != 1]
def get_sub_list(my_list):
"""will split the list base on the index"""
my_index = split_list(my_list)
output = list()
prev = 0
for index in my_index:
new_list = [ x for x in my_list[prev:] if x < index]
output.append(new_list)
prev += len(new_list)
output.append([ x for x in my_list[prev:]])
return output
my_list = [1, 3, 4, 7, 8, 10, 11, 13, 14]
print get_sub_list(my_list)
Ausgabe:
[[1], [3, 4], [7, 8], [10, 11], [13, 14]]
Ich hatte ein ähnliches Problem und verwende Folgendes für eine sortierte Liste. Es gibt ein Wörterbuch mit in einem Wörterbuch aufgelisteten Wertebereichen aus. Die Tasten trennen jeden Lauf aufeinanderfolgender Nummern und sind auch die laufende Summe nicht aufeinanderfolgender Elemente zwischen aufeinander folgenden Nummern.
Ihre Liste gibt mir eine Ausgabe von {0: [1, 4], 1: [7, 8], 2: [10, 14]}
def series_dictf(index_list):
from collections import defaultdict
series_dict = defaultdict(list)
sequence_dict = dict()
list_len = len(index_list)
series_interrupts = 0
for i in range(list_len):
if i == (list_len - 1):
break
position_a = index_list[i]
position_b = index_list[i + 1]
if position_b == (position_a + 1):
sequence_dict[position_a] = (series_interrupts)
sequence_dict[position_b] = (series_interrupts)
if position_b != (position_a + 1):
series_interrupts += 1
for position, series in sequence_dict.items():
series_dict[series].append(position)
for series, position in series_dict.items():
series_dict[series] = [position[0], position[-1]]
return series_dict
Mit der Set-Operation kann der folgende Algorithmus ausgeführt werden
def get_consecutive_integer_series(integer_list):
integer_list = sorted(integer_list)
start_item = integer_list[0]
end_item = integer_list[-1]
a = set(integer_list) # Set a
b = range(start_item, end_item+1)
# Pick items that are not in range.
c = set(b) - a # Set operation b-a
li = []
start = 0
for i in sorted(c):
end = b.index(i) # Get end point of the list slicing
li.append(b[start:end]) # Slice list using values
start = end + 1 # Increment the start point for next slicing
li.append(b[start:]) # Add the last series
for sliced_list in li:
if not sliced_list:
# list is empty
continue
if len(sliced_list) == 1:
# If only one item found in list
yield sliced_list[0]
else:
yield "{0}-{1}".format(sliced_list[0], sliced_list[-1])
a = [1, 2, 3, 6, 7, 8, 4, 14, 15, 21]
for series in get_consecutive_integer_series(a):
print series
Ausgabe für die obige Liste "a"
1-4
6-8
14-15
21