Pracuję nad moim pierwszym programem funkcjonalnymw Clojure. Mam problemy z ustaleniem, jak przejść przez każdy element na liście, na każdej liście na liście i operować nim, zachowując wartości zwracane. Jestem pewien, że problem wynika z mojej nieznajomości Clojure i programowania funkcjonalnego oraz miał nadzieję, że ktoś wyjaśni najlepszą metodę wykonania następujących czynności:
psuedo-code algorithm:
for each lst in list
for each item in lst
return_values.append = do_something(item)
Najpierw próbowałem zagnieździć dwa doseq
funkcje, a następnie wywoływanie mojego do_something
funkcja, która działała, aby wywołać funkcję na elemencie, ale nie zapisała moich wartości zwracanych. Następnie spróbowałem for
i cons
do pustej listy, ale nie udało mi się uzyskać wartości zwracanych poza for
.
Czy byłoby możliwe / najlepiej najpierw rozbić listę list? Czy nadal mogę uzyskać listę list wartości zwracanych?
Na koniec chciałbym, aby wynik był listąlist wartości zwracanych, aby pasowały do wejściowej listy list. Gdyby ktoś mógł wyjaśnić najlepszą metodę zrobienia tego w Clojure i dlaczego, byłby bardzo wdzięczny.
Odpowiedzi:
5 dla odpowiedzi № 1Zagnieżdżony for
Pętla załatwi sprawę:
(for [lst my-list]
(for [item lst] (do_something item)))
Zajmie listę zagnieżdżoną my-list
(lista list) i przekonwertuj ją na inną listę zagnieżdżoną, stosując do_something
do każdego elementu.
W clojure for
zwraca już listę wartości, więc nie matrzeba sobie z tym poradzić. Ponadto, ponieważ wszystkie struktury danych w clojure są niezmienne, nie można tego zrobić, dodając elementy do początkowo pustej listy za pomocą cons
.
0 dla odpowiedzi nr 2
Jeśli masz głęboko zagnieżdżoną listę i chcesz zachować jej strukturę, ale przekształcić wartości, możesz użyć clojure.walk/postwalk
do obsługi każdej wartości, np .:
(def nested "(1 (2 3 (4 5)) 6))
(defn transform-values [coll f]
(clojure.walk/postwalk #(if (not (list? %))
(f %)
%)
coll))
(transform-values nested inc)
=> (2 (3 4 (5 6)) 7)
Możesz oczywiście przekazać dowolną funkcję transform-values
.
0 dla odpowiedzi № 3
Można to zrobić jako zwykły marsz rekurencyjny. Pierwszą implementacją, która przychodzi na myśl, będzie następująca sekwencja:
(defn deep-walk
[f data]
(map (fn [s] (if (seq? s)
(deep-walk f s)
(f s)))
data))
I ta niewielka zmiana dla wektorów:
(defn vec-deep-walk
[f data]
(vec (map (fn [s] (if (vector? s)
(vec-deep-walk f s)
(f s)))
data)))
Szybki test z następującymi elementami:
(vec-deep-walk (partial + 1) [1 [2 3] 4 [5 [6 7]]])
Daje następujące dane wyjściowe:
[2 [3 4] 5 [6 [7 8]]]
Funkcje marszu mają dwa parametry, pierwszyto funkcja, która przyjmuje pojedynczy parametr. Zostanie to wywołane dla każdego elementu nie będącego sekwencją / w danych, który jest przekazywany jako drugi parametr. Wyniki zostaną zwrócone w zagnieżdżonej strukturze, która jest identyczna ze strukturą wejściową.