ich gehe davon aus, dass Sub-Arrays mitAnfangund endend mit ":/desc"
, und enthalten keine anderen Instanzen von ":/desc"
, sind extrahiert werden. Beachten Sie, dass arr = [":desc:", ":desc:", ":/desc"]
, [a]
zurückgegeben wird. Ich habe keine Annahmen über die Struktur des Arrays gemacht (aber ich habe nicht alle Möglichkeiten getestet). Wenn bestimmte Annahmen gemacht werden (beispielsweise die Existenz von übereinstimmenden, nicht überlappenden Paaren), sind Vereinfachungen möglich.
-Code
def extract(arr, target_start, target_end)
arr.select { |s| (s == target_start)..(s == target_end) ? true : false }.
slice_when { |s,t| [s, t] == [target_end, target_start] }.
to_a.
tap { |a| a.pop unless a.last.last == target_end }
end
Beispiele
target_start = ":desc:"
target_end = ":/desc"
arr = ["hello", ":desc:", "claire", "et", "concise", ":/desc",
":desc:", "claire", "caca", "concise", "test", ":/desc"]
extract(arr, target_start, target_end)
#=> [[":desc:", "claire", "et", "concise", ":/desc"],
# [":desc:", "claire", "caca", "concise", "test", ":/desc"]]
arr = ["hello", ":desc:", "claire", "et", "concise", ":/desc", "wanda",
":desc:", "claire", "caca", "concise", "test", ":/desc", "herb"]
extract(arr, target_start, target_end)
# => [[":desc:", "claire", "et", "concise", ":/desc"],
# [":desc:", "claire", "caca", "concise", "test", ":/desc"]]
arr = ["hello", ":desc:", "claire", "et", "concise", ":/desc",
":desc:", "claire", "caca", "concise", "test"]
extract(arr, target_start, target_end)
#=> [[":desc:", "claire", "et", "concise", ":/desc"]]
arr = ["hello", ":desc:", "claire", "et", "concise", ":desc:", "claire",
"caca", "concise", "test"]
extract(arr, target_start, target_end)
#=> []
Erklärung
Betrachten
arr = ["hello", ":desc:", "claire", "et", "concise", ":/desc",
":desc:", "claire", "caca", "concise", "test"]
und target_start
und target_end
wie im Beispiel angegeben. Die Schritte sind wie folgt.
b = arr.select { |s| (s == target_start)..(s == target_end) ? true : false }
#=> [":desc:", "claire", "et", "concise", ":/desc", ":desc:", "claire",
# "caca", "concise", "test"]
Dieser erste Schritt, der flip-flop operator Verwendung von Ruby macht, gibt ein Array, das alle Elemente der arr
mit Ausnahme derjenigen, die precede enthält die erste ":desc:"
und diejenigen, die zwischen zwischen jedem ":/desc"
und dem ersten ":desc:"
sind, die folgt.
Als nächstes verwenden wir Enumerable#slice_when (neu in Ruby v2.2), um einen Enumerator zu erstellen, der b
wie gewünscht schneidet und dann diesen Enumerator in ein Array konvertiert.
c = b.slice_when { |s,t| [s, t] == [target_end, target_start] }
#=> #<Enumerator: #<Enumerator::Generator:0x00000001dd4f18>:each>
d = c.to_a
#=> [[":desc:", "claire", "et", "concise", ":/desc"],
# [":desc:", "claire", "caca", "concise", "test"]]
Der letzte Schritt ist die letzte Reihe von d
zu entfernen, wenn sie nicht mit ":/desc"
, was hier der Fall ist, nicht beenden. Wir können dafür verwenden, aber nicht direkt, da es das popping-Element zurückgibt, was dazu führen würde, dass die Methode auch diesen Wert zurückgibt. Wenn wir es jedoch in einem Object#tap Block verwenden, ist alles in Ordnung.
d.tap { |a| a.pop unless a.last.last == target_end }
#=> [[":desc:", "claire", "et", "concise", ":/desc"]]
Könnte es ein Tippfehler sein? Array Elemente sind '":/desc "' aber du hast 'end_element =":/desc: "' – Marco