[Uwaga: Tytuł i tekst były mocno edytowane, aby było bardziej zrozumiałe, że nie jestem szczególnie po ciągach, ale po ogólnych sekwencjach i leniwym przetwarzaniu sama]Najlepszy sposób na leniwe zwijanie wielu przylegających elementów sekwencji do pojedynczego elementu
Korzystanie sekwencje znaków/ciągi jako przykład, że chcę zamienić ciąg jak
„\ ta \ r s \ td \ t \ r \ n f \ r \ n”
do
"asdf"
W kategoriach bardziej ogólnych, chce się wyłączyć wszystkie sąsiadujące ze sobą odstępy (lub innego arbitray zestaw przedmiotów) w sekwencji w pojedynczy przedmiot, i to leniwie.
Wpadłem na następujący zestaw partition-by/mapcat combo, ale zastanawiam się, czy istnieją łatwiejsze lub w inny sposób lepsze sposoby (czytelność, wydajność, cokolwiek), aby osiągnąć to samo.
(defn is-wsp?
[c]
(if (#{\space \tab \newline \return} c) true))
(defn collapse-wsp
[coll]
(mapcat
(fn [[first-elem :as s]]
(if (is-wsp? first-elem) [\space] s))
(partition-by is-wsp? coll)))
w akcji:
=> (apply str (collapse-wsp "\t a\r s\td \t \r \n f \r\n"))
" a s d f "
aktualizacji: użyłem strun/sekwencje znaków/WSP, jako przykład, ale to, co rzeczywiście chcesz to ogólna funkcja na sekwencjach dowolnego typu, które zwija dowolne liczby sąsiednich elementów, które są częścią wstępnie zdefiniowanego zestawu elementów, za pomocą jakiegoś pojedynczego predefiniowanego elementu. Szczególnie interesuje mnie, czy istnieją lepsze alternatywy dla partition-by/mapcat, nie tak bardzo, jeśli można to zoptymalizować dla specjalnego przypadku 'string'.
Aktualizacja 2:
Oto całkowicie leniwy wersja - ten powyżej, nie jest w pełni leniwy, obawiam się, oprócz tego, że robi się zbędne IS-WSP? czeki. Uogólniłem nazwy parametrów itp., Więc nie tylko wygląda to na coś, co można łatwo zastąpić wywołaniem String.whatever() - chodzi o arbitralne sekwencje.
(defn lazy-collapse
([coll is-collapsable-item? collapsed-item-representation] (lazy-collapse coll is-collapsable-item? collapsed-item-representation false))
([coll is-collapsable-item? collapsed-item-representation in-collapsable-segment?]
(let [step (fn [coll in-collapsable-segment?]
(when-let [item (first coll)]
(if (is-collapsable-item? item)
(if in-collapsable-segment?
(recur (rest coll) true)
(cons collapsed-item-representation (lazy-collapse (rest coll) is-collapsable-item? collapsed-item-representation true)))
(cons item (lazy-collapse (rest coll) is-collapsable-item? collapsed-item-representation false)))))]
(lazy-seq (step coll in-collapsable-segment?)))))
ten jest szybki, w pełni leniwy, ale chciałbym być w stanie wyrazić, że bardziej zwięźle, ponieważ jestem dość leniwy siebie.
Wzorce leniwych collapsers dotychczas: czy kod jest czytelny lub nie jest łatwo ocenić, patrząc na kod, ale żeby zobaczyć ich porównanie pod względem wydajności, tutaj są moje benchmarków.I najpierw sprawdzić, czy funkcja robi to, co ma robić, a potem wypluć jak długo to trwa do
- utworzyć leniwy nast 1M razy
- utworzyć leniwy nast i wziąć pierwszy element 1M razy
- utworzyć leniwy nast i wziąć drugi element 1M razy
- utworzyć leniwy nast i wziąć ostatni element (czyli w pełni uświadomić sobie leniwe nast) 1M razy
prób od 1 do 3 są przeznaczone do miernika lenistwo co najmniej li trochę. Przeprowadziłem test kilka razy i nie było żadnych znaczących zmian w czasach wykonania.
user=> (map
(fn [collapse]
(println (class collapse) (str "|" (apply str (collapse test-str is-wsp? \space)) "|"))
(time (dotimes [_ 1000000] (collapse test-str is-wsp? \space)))
(time (dotimes [_ 1000000] (first (collapse test-str is-wsp? \space))))
(time (dotimes [_ 1000000] (second (collapse test-str is-wsp? \space))))
(time (dotimes [_ 1000000] (last (collapse test-str is-wsp? \space)))))
[collapse-overthink collapse-smith collapse-normand lazy-collapse])
user$collapse_overthink | a s d f |
"Elapsed time: 153.490591 msecs"
"Elapsed time: 3064.721629 msecs"
"Elapsed time: 4337.932487 msecs"
"Elapsed time: 24797.222682 msecs"
user$collapse_smith | a s d f |
"Elapsed time: 141.474904 msecs"
"Elapsed time: 812.998848 msecs"
"Elapsed time: 2112.331739 msecs"
"Elapsed time: 10750.224816 msecs"
user$collapse_normand | a s d f |
"Elapsed time: 314.978309 msecs"
"Elapsed time: 1423.779761 msecs"
"Elapsed time: 1669.660257 msecs"
"Elapsed time: 8074.759077 msecs"
user$lazy_collapse | a s d f |
"Elapsed time: 169.906088 msecs"
"Elapsed time: 638.030401 msecs"
"Elapsed time: 1195.445016 msecs"
"Elapsed time: 6050.945856 msecs"
Konkluzja tej pory: Najpiękniejszy kod jest najwolniejsza, najbrzydszy kod jest najszybszy. Jestem prawie pewien, że to nie musi tak być ...
Po prawie roku teraz, pozwól mi zaakceptować twoją odpowiedź. Nie jest to najszybszy, ale może dobry kompromis między wydajnością a zwięzłością/czytelnością. – SuperHorst