2016-10-17 3 views
0

Ich habe ein Array von Strings:effizienter als gsub zweimal

orders = ["#1174.2", "#1176.3", "#1177.2", "#1178.1", "#1180.1"] 

Ich tue dies die führende „#“ zu entfernen und „0,1"

orders.each do |numbers| 
    puts numbers.gsub!("#", "").gsub!(/\.[0-9]/, "") 
end 
# returns 1174, 1176 etc.. 

das nachlaufHinter“ .1 "könnte eine beliebige Zahl bis 9 sein. Gibt es einen besseren/schnelleren Weg dies zu tun?

+0

Auch, FWIW, würden Sie wahrscheinlich gsub, nicht gsub verwenden möchten! für dein Beispiel. Die Bang-Methoden sind in der Regel nicht gut verkettet, da sie nur die Zeichenfolge zurückgeben, wenn Substitutionen durchgeführt wurden - dies könnte zu kleinen Fehlern führen. https://ruby-doc.org/core-2.1.4/String.html#method-i-gsub –

+0

Haben die Zahlen immer das gleiche Format, d. h. vier Ziffern, eine Dezimalzahl und eine einzelne Ziffer? –

+0

Erwarten Sie, dass die Zahlen richtig gerundet werden? –

Antwort

2
cleaned_orders = orders.map { |numbers| numbers.gsub(/(^#|\.\d$)/, '') } 

cleaned_orders jetzt enthält: ['1174', '1176', '1177', '1178', '1180']

(^#|\.\d$) Matches # wenn es am Anfang des Strings oder einer einzigen Periode durch eine einzige Ziffer am Ende der Zeichenfolge folgt.

-2

Verwenden Sie diesen

orders.join.gsub(/\.[0-9]#/, "#").gsub(/\.[0-9]/, "").split("#") - [""] 

Returns

=> ["1174", "1176", "1177", "1178", "1180"] 

Durchbruch

Dieses Verfahren dauert 5 Stufen. Dies ist unabhängig davon, wie viele Elemente Sie in Array haben.

2.2.5 :019 > orders.join 
=> "#1174.2#1176.3#1177.2#1178.1#1180.1" 
2.2.5 :020 > orders.join.gsub(/\.[0-9]#/, "#") 
=> "#1174#1176#1177#1178#1180.1" 
2.2.5 :021 > orders.join.gsub(/\.[0-9]#/, "#").gsub(/\.[0-9]/, "") 
=> "#1174#1176#1177#1178#1180" 
2.2.5 :022 > orders.join.gsub(/\.[0-9]#/, "#").gsub(/\.[0-9]/, "").split("#") 
=> ["", "1174", "1176", "1177", "1178", "1180"] 
2.2.5 :023 > orders.join.gsub(/\.[0-9]#/, "#").gsub(/\.[0-9]/, "").split("#") - [""] 
=> ["1174", "1176", "1177", "1178", "1180"] 
+0

Ich habe meine Antwort aktualisiert, bitte sieh sie dir an. – dnsh

+0

Es ist ein bisschen komplex für die Aufgabe. –

+0

Ja, das ist komplexer als meine ursprüngliche Reihe von Methoden – ToddT

4

Eine Möglichkeit, dies zu tun:

orders.map { |s| s.sub('#','').to_i } 
#=> [1174, 1176, 1177, 1178, 1180] 

hinzufügen to_s in den Block, wenn Sie Strings wollen.


Falls das OP die Zahlen abgerundet haben möchte. z.B. #1174.8 kehrt 1175 usw. Dann sollte dieser den Trick:

orders = ["#1174.2", "#1176.5", "#1177.2", "#1178.7", "#1180.1"] 
#=> ["#1174.2", "#1176.5", "#1177.2", "#1178.7", "#1180.1"]  

orders.map { |s| s.sub('#','').to_f.round.to_s } 
#=> ["1174", "1177", "1177", "1179", "1180"] 
+0

Nun, diese befasst sich nicht mit der nachlaufenden Periode und Nummer. – ToddT

+3

Wie geht es nicht mit der nachlaufenden Periode und Nummer? –

0

etwas Versuchen Sie, wie dieses

orders.map { |item| item.gsub(/#(\d+)(\.\d)?/, '\1') } 
=> ["1174", "1176", "1177", "1178", "1180"] 

Dies auch dann, wenn einige Elemente funktioniert nicht einen Punkt etwas Ende hat.

3

Ich würde verwenden:

orders = ["#1174.2", "#1176.3", "#1177.2", "#1178.1", "#1180.1"] 
orders.map{ |n| n[/\d+/] } # => ["1174", "1176", "1177", "1178", "1180"] 

/\d+/ wird die erste Gruppe von Ziffern gefunden zurückgeben, was bedeutet, dass '#' und .n automatisch ignoriert.

Hier ist ein Benchmark:

require 'fruity' 

orders = ["#1174.2", "#1176.3", "#1177.2", "#1178.1", "#1180.1"] 

compare do 
ttm { orders.map{ |n| n[/\d+/] } } 
ursus { orders.map { |item| item.gsub(/#(\d+)(\.\d)?/, '\1') } } 
dinesh { orders.join.gsub(/\.[0-9]#/, "#").gsub(/\.[0-9]/, "").split("#") - [""] } 
sagarpandya82 { orders.map { |s| s.sub('#','').to_i.to_s } } 
infused { orders.map { |numbers| numbers.gsub(/(^#|\.\d$)/, '') } } 
end 

# >> Running each test 1024 times. Test will take about 1 second. 
# >> ttm is faster than sagarpandya82 by 60.00000000000001% ± 10.0% 
# >> sagarpandya82 is faster than dinesh by 2.0x ± 0.1 
# >> dinesh is faster than infused by 39.99999999999999% ± 10.0% 
# >> infused is faster than ursus by 10.000000000000009% ± 10.0% 
+1

Dies ist eindeutig die beste Regex unter den vorgeschlagenen. Es ist nicht nur das einfachste, es liest sich am besten: wie Sie sagen (sic), "gebe die erste gefundene Ziffernfolge zurück". –

1

Es sieht aus wie alle Zahlen vier Ziffern haben. Wenn das immer wahr ist, möchten Sie vielleicht, dies versuchen:

orders = ["#1174.2", "#1176.3", "#1177.2", "#1178.1", "#1180.1"] 
orders.map { |n| n[1..-3] } 
#=> ["1174","1176","1177","1178","1180"] 

Dies funktioniert natürlich nur, wenn alle Zahlen das gleiche Format und Länge haben, aber es ist viel schneller als ein regulärer Ausdruck verwendet wird.

1
orders.map { |s| s[1..-1].to_i.to_s } 
    #=> ["1174", "1176", "1177", "1178", "1180"] 

entfernen .to_s wenn Sie ein Array von ganzen Zahlen, anstatt ein Array von Strings wollen.

+0

Problem mit 'to_i' ist, dass es z. '1774.6.to_i' wird' 1774' geben, aber wahrscheinlich wollen wir wirklich '1775'. Habe das gerade erst bemerkt und meine Antwort bearbeitet. Obwohl das OP (oder andere Antworten) dies erwähnen/erklären, muss dies sicherlich der richtige Ansatz sein. –

+1

@ sagarpandya82, können wir nicht sagen. Wenn ich zum Beispiel meine Steuern einreiche, runden unsere Steuerleute einige Beträge auf den nächsten Dollar ab. Todd hat gesagt, dass die Kürzung gewünscht ist ("The Trailing" .1 "könnte eine beliebige Zahl bis 9 sein.") –