web-dev-qa-db-de.com

Ermitteln von aufeinander folgenden Ganzzahlen in einer Liste

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?

44
James

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.

68
Dominic Rodger

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 :-)

3
TToni

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
2
dansalmo

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)]
2
coldfix

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]]
0
James Sapam

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
0

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 

0
theBuzzyCoder