Extrahieren ganzzahliger Teilfolgen, die mit einer wiederholten Zahl beginnen

-1

Ich habe eine Datei, die eine einzelne Spalte von ganzen Zahlen enthält. Ich möchte aus dieser Datei die Liste aller zusammenhängenden Teilfolgen (dh Teilfolgen, die in aufeinanderfolgender Reihenfolge auftreten) extrahieren, die zweimal hintereinander mit der gleichen Nummer beginnen und eine Länge von 12 ganzen Zahlen haben (einschließlich überlappender Teilfolgen).

Darüber hinaus sollten alle nicht ganzzahligen Zeilen in der Datei ignoriert / entfernt werden. Wenn eine Sequenz das Ende der Eingabe erreicht, bevor 12 Ganzzahlen erreicht sind, sollte die verkürzte Sequenz weiterhin ausgegeben werden.

Angenommen, meine Eingabedatei enthält die folgenden Daten:

1
junk
1

1
2
3
4
4
5
6
7
8
9
10
11
12
13
14
15
15
16

Dann sollte die Lösung die folgende Ausgabe erzeugen:

1 1 1 2 3 4 4 5 6 7 8 9
1 1 2 3 4 4 5 6 7 8 9 10
4 4 5 6 7 8 9 10 11 12 13 14
15 15 16

Beachten Sie, dass die junkZeile und die leere Zeile ignoriert werden, sodass die ersten drei 1Zeilen als zusammenhängend behandelt werden.

Asmodeus
quelle
Ich würde nicht sagen, dass Sie zwei aufeinanderfolgende Nummern finden möchten. Zwei aufeinanderfolgende Nummern möchten 1,2oder 5,6. Ich würde sagen, dass Sie die gleiche Zahl zweimal an zwei aufeinanderfolgenden Stellen finden möchten.
igal
Was wäre, wenn es weniger als 10 Ziffern nach zwei entscheidenden doppelten Ziffern geben würde? Sollte es den Rückstand trotzdem in eine Datei drucken?
RomanPerekhrest
Was ist, wenn auch in diesen 10 Zeilen identische fortlaufende Nummern vorhanden sind?
Stéphane Chazelas

Antworten:

1

Hier ist ein Python-Skript, das macht, was Sie wollen:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""extract_subsequences.py"""

import sys
import re

# Open the file
with open(sys.argv[1]) as file_handle:

    # Read the data from the file
    # Remove white-space and ignore non-integers
    numbers = [
        line.strip()
        for line in file_handle.readlines()
        if re.match("^\d+$", line) 
    ]

    # Set a lower bound so that we can output multiple lists
    lower_bound = 0
    while lower_bound < len(numbers)-1:

        # Find the "start index" where the same number
        # occurs twice at consecutive locations
        start_index = -1 
        for i in range(lower_bound, len(numbers)-1):
            if numbers[i] == numbers[i+1]:
                start_index = i
                break

        # If a "start index" is found, print out the two rows
        # values and the next 10 rows as well
        if start_index >= lower_bound:
            upper_bound = min(start_index+12, len(numbers))
            print(' '.join(numbers[start_index:upper_bound]))

            # Update the lower bound
            lower_bound = start_index + 1

        # If no "start index" is found then we're done
        else:
            break

Angenommen, Ihre Daten befinden sich in einer Datei mit dem Namen data.txt. Dann könnten Sie dieses Skript wie folgt ausführen:

python extract_subsequences.py data.txt

Angenommen, Ihre Eingabedatei data.txtsieht folgendermaßen aus:

1
1
1
2
3
4
5
6
7
8
9
10
11
12

Dann würde Ihre Ausgabe so aussehen:

1 1 1 2 3 4 5 6 7 8 9 10
1 1 2 3 4 5 6 7 8 9 10 11

Verwenden Sie die Ausgabeumleitung, um die Ausgabe in einer Datei zu speichern:

python extract_subsequences.py data.txt > output.txt
igal
quelle
0

AWK Ansatz:

Berücksichtigt man nur zuerst 2 identische aufeinanderfolgende Zahlen, so ist dies für mehrere Extraktionen geeignet, ohne jedoch die Bedingung zu berücksichtigen, dass 2 identische aufeinanderfolgende Zahlen innerhalb der folgenden 10-Nummern-Sequenz unter dem verarbeiteten Slice liegen können.

awk 'NR==n && $1==v{ print v ORS $1 > "file"++c; tail=n+11; next }
     { v=$1; n=NR+1 }NR<tail{ print > "file"c }' file
RomanPerekhrest
quelle
@asmodeus, kopiere und füge es aufmerksam ein. Ja, es sollte als eine Zeile ausgeführt werden
RomanPerekhrest
0

Erste Variante - O (n)

awk '
/^[0-9]+$/{
    arr[cnt++] = $0;
}

END {
    for(i = 1; i < cnt; i++) {
        if(arr[i] != arr[i - 1])
            continue;

        last_element = i + 11; 
        for(j = i - 1; j < cnt && j < last_element; j++) {
            printf arr[j] " ";
        }
        print "";
    }
}' input.txt

Zweite Variante - O (n * n)

awk '
BEGIN {
    cnt = 0;
}

/^[0-9]+$/{
    if(prev == $0) {
        arr[cnt] = prev;
        cnt_arr[cnt]++;
        cnt++;
    }

    for(i = 0; i < cnt; i++) {
        if(cnt_arr[i] < 12) {
            arr[i] = arr[i] " " $0; 
            cnt_arr[i]++;
        }
    }

    prev = $0;        
}

END {
    for(i = 0; i < cnt; i++)
        print arr[i];
}' input.txt

Ausgabe

1 1 1 2 3 4 4 5 6 7 8 9
1 1 2 3 4 4 5 6 7 8 9 10
4 4 5 6 7 8 9 10 11 12 13 14
15 15 16
MiniMax
quelle
@asmodeus Wenn Sie awk -f filemethod verwenden, sollten Sie awk 'vom Anfang und ' input.txtvom Ende des Skripts entfernen . Und es durch diese Art und Weise auszuführen: awk -f script.awk input.txt. Sie können auch einfach alle Befehle ( awkSkripte) in das Terminal kopieren und drücken Enter.
MiniMax
@asmodeus Der dritte Weg (die ich lieber): der vollständigen Befehl in den Putting - bashSkript (benannt my_program.sh, zum Beispiel), dann macht es ausführbar durch die chmod u+x my_program.shund durch den Lauf ./my_program.sh. Vergessen Sie nicht den bashSchebang - #!/bin/basham Anfang der my_program.shAkte.
MiniMax
@asmodeus "Der zweite hängt gerade und produziert keine Ausgabe." Wann kopieren Sie alle Befehle in das Terminal? Ich habe sie gerade auf diese Weise überprüft. Beide arbeiten.
MiniMax