2012-02-02 11 views
9

W Clojure, jaki jest najlepszy sposób na równoczesne iterowanie na dwóch seqs i wywoływanie funkcji na dwóch elementach uruchomionych? Na przykład:clojure jak uruchomić funkcję na elementach dwóch seqs concurently?

(def a (range 3)) 
(def b (range 100 103)) 
(defn my-func [] ...) ;some custom code 

Kod powinien wykonywać moje func-3 razy, tak:

(my-func 0 100) 
(my-func 1 101) 
(my-func 2 102) 

Jak mogę to osiągnąć bez definiowania dowolnej funkcji lub makro?

+1

(zakres 100 102) ma tylko dwa elementy - być może masz na myśli (zakres 100 103)? – mikera

+0

@mikera: dzięki. zaktualizowano pytanie – viebel

Odpowiedz

15

map jest dokładnie tym, czego potrzebujesz, zajmuje funkcję i dowolną liczbę numerów seq i wywołuje je tak, jak chcesz.

(def a (range 3)) 
(def b (range 100 103)) 
user=> a 
(0 1 2) 
user=> b 
(100 101 102) 

user=> (defn my-func [a b] (str a ":" b)) 
#'user/my-func 

user=> (my-func 1 2) 
"1:2" 

user=> (map my-func a b) 
("0:100" "1:101" "2:102") 

i dlatego map jest leniwy, jeśli chcesz funkcja faktycznie uruchomić teraz:

(doall (map my-func a b)) 
+0

To nie działa. To wyjście: (0: 100 1: 101 zero zero) – viebel

+0

@viebel: Czy korzystasz z REPL i używasz 'println'? Jeśli tak, twoje wyniki są mylące. Zakładając, że uruchomiłeś '(map # (println% 1": "% 2) ab)', zdarzyło się, że REPL wydrukował '(', następnie 'println' wydrukował' 0: 100' i '1: 101', następnie REPL zakończył drukowanie wyników mapy, która jest zerowa). – mange

+0

zero zero to powrót prinln zanim go zredagowałem –

3

Można również spróbować

(doseq [[x y] (map list my-list1 my-list2)] 
    (println x y)) 

(map list list-2 list-2) tworzy listę, w której pierwszym elementem jest lista pierwszych elementów list wejściowych, drugim elementem jest lista drugich elementów, ...

Następnie wykonujemy iterację na liście, używając destrukturyzacji Clojure w celu wyodrębnienia elementów z pierwotnych list.

Ogólnie rzecz biorąc, chcesz map, jeśli chcesz użyć zwracanej wartości funkcji, którą aplikujesz. Jeśli po prostu wykonujesz funkcję efektów ubocznych, generalnie używam doseq. Ten przypadek jest skomplikowany przez fakt, że map działa równolegle, podczas gdy doseq iteruje nad Cartesian Product z list, które są podane, więc aby uzyskać pożądane działanie, potrzebujesz zarówno map, jak i .

+0

Czy istnieje funkcja podobna do dawkiq, która iteruje równolegle, a nie nad produktem kartezjańskim. Jeśli nie, jakie jest uzasadnienie? – viebel

+0

O ile mi wiadomo, nie ma takiej funkcji. Idealnie doseq/for (mają tę samą składnię) pozwoliłoby na coś takiego jak: oraz opcję pozwalającą na dwie równoległe iteracje. Niestety taka opcja nie istnieje. – Retief

0

Alternatywą do rozwiązania (doseq ... (map, jeśli chcesz parami iteracji zamiast iloczyn kartezjański, można również połączyć partition z interleave tak:

> (def a (range 0 3)) 
> (def b (range 100 103)) 
> (interleave a b) 
(0 100 1 101 2 102) 
> (partition 2 (interleave a b)) 
((0 100) (1 101) (2 102)) 

partition wezwanie dostarcza (lazy) SEQ par.

Powiązane problemy