2017-06-29 6 views
3

Ich habe versucht, eine gängige Zeichenfolge Darstellung von Bereichen (z. B. 1-9) in tatsächliche Bereiche (z. B. 1 .. 9) zu analysieren, aber oft seltsame Ergebnisse erhalten, wenn zweistellige Zahlen enthalten. 1-10 Ergebnisse im Einzelwert zum Beispiel 1 statt eine Liste von zehn Werten und 11-20 gaben mir vier Werte (11 10 21 20), die Hälfte davon sind nicht einmal in dem erwarteten Zahlenbereich:Warum sind einige meiner Bereiche wahnsinnig?

put get_range_for('1-9'); 
put get_range_for('1-10'); 
put get_range_for('11-20'); 

sub get_range_for ($string) { 

    my ($start, $stop) = $string.split('-'); 

    my @values = ($start .. $stop).flat; 

    return @values; 
} 

Diese Drucke:

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

Statt der erwarteten:

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

(Ich habe das vor dem Posten dieser Frage herausgefunden, also habe ich unten geantwortet. Fühlen Sie sich frei, Ihre eigene Antwort hinzuzufügen, wenn Sie es ausarbeiten möchten).

Antwort

9

Das Problem ist in der Tat, dass .split kehrt Str statt Int, die die ursprüngliche Antwort löst. Allerdings würde ich lieber meine „get_range_for“ wie folgt implementieren:

sub get_range_for($string) { 
    Range.new(|$string.split("-")>>.Int) 
} 

Dieses ein Range Objekt eher als ein Array zurückkehren würde. Aber für die Iteration (wofür Sie wahrscheinlich das verwenden würden) würde dies keinen Unterschied machen. Auch für größere Bereiche könnte die andere Implementierung von "get_range_for" möglicherweise eine Menge Speicher verbrauchen, weil sie die Range in eine Array vivifiziert. Dies ist für "3-10" nicht sehr wichtig, würde aber für "1-10000000" gelten.

Beachten Sie, dass diese Implementierung >>.Int verwendet die Int-Methode für alle Werte aus den .split zurückrufen, und dann rutscht sie als separater Parameter mit | zu Range.new. Dies wird dann auch bombardieren, wenn .split den Wert 1 zurückgibt (wenn es nicht geteilt werden konnte) oder mehr als 2 Werte (wenn mehrere Bindestriche in der Zeichenfolge aufgetreten sind).

+0

das nicht fast genug Sonderzeichen verwendet - wie wäre es mit '& [..] (| + << $ string.split ('-'))' stattdessen: p – Christoph

+1

Ich finde die Lesbarkeit von 'Range.new' höher als' & [..] '. –

+0

@Christoph Schönes Beispiel. Bitte posten Sie das als eine andere Antwort. Wer Subs braucht, kann einfach '& [..] (| + << $ string.split ('-')) '? :) –

7

Das Ergebnis von split ist ein Str, so dass Sie versehentlich eine Reihe von Zeichenfolgen anstelle eines Bereichs von ganzen Zahlen erstellen. Versuchen Sie $start und $stop-Int Umwandlung vor den Bereich zu schaffen:

put get_range_for('1-9'); 
put get_range_for('1-10'); 
put get_range_for('11-20'); 

sub get_range_for ($string) { 

    my ($start, $stop) = $string.split('-'); 

    my @values = ($start.Int .. $stop.Int).flat; # Simply added .Int here 

    return @values; 
} 

Sie geben, was Sie erwarten:

1 2 3 4 5 6 7 8 9 
1 2 3 4 5 6 7 8 9 10 
11 12 13 14 15 16 17 18 19 20 
+2

Dieser Ansatz ist in Ordnung, aber für größere Bereiche könnte möglicherweise eine Menge Speicher essen, weil Sie die Range beleben. Ich würde dies schreiben als: 'sub get_range_for ($ string) {Bereich.neu (| $ string.split (" - ") >>. Int)}'. Dies würde das Range-Objekt zurückgeben, das Sie später über * oder * in einem Array speichern können, sollten Sie dies wünschen. Beachten Sie, dass dies '>>. Int' verwendet, um die' Int'-Methode für alle Werte aufzurufen, die von '.split' zurückgegeben werden, und sie dann als separate Parameter mit' || nach 'Range.new' ausgibt. –

+0

@ElizabethMattijsen Guter Anruf. Manchmal kann die Erinnerung ein Problem sein. Bitte erstellen Sie eine Antwort und fügen Sie Ihre Lösung hinzu. –

+0

Ihr Wunsch ist mein Befehl :-) –

Verwandte Themen