2015-12-24 14 views
6

Jestem nowy w Clojure i trudno mi w idiomatyczny sposób wprowadzić podstawowe manipulacje w strukturach danych.Co to jest idiomatyczny sposób na wprowadzenie podwójnej pętli przez wektor w Clojure?

Jaki byłby idiomatyczny sposób wdrożenia następującego kodu w Clojure?

l = [...] 
for i in range(len(l)): 
    for j in range(i + 1, len(l)): 
    print l[i], l[j] 
+0

Jak już wspomniano, 'doseq' jest sposobem. Ale kiedy chcesz manipulować danymi, prawdopodobnie szukasz 'map' lub' for'. – user5187212

Odpowiedz

4

najprostszych (ale nie najbardziej FP-owski) jest niemal identyczny do przykładu:

(let [v [1 2 3 4 5 6 7]] 
    (doseq [i (range (count v)) 
      j (range (inc i) (count v))] 
    (println (v i) (v j)))) 

i tutaj jest bardziej funkcjonalny wariant, aby wygenerować te wszystkie pary (to nie jest oparte na długość lub wskaźniki, ale raczej na iteracji ogona)

(let [v [1 2 3 4 5 6 7]] 
    (mapcat #(map (partial vector (first %)) (rest %)) 
      (take-while not-empty (iterate rest v)))) 

Wydajność:

([1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [2 3] [2 4] 
    [2 5] [2 6] [2 7] [3 4] [3 5] [3 6] [3 7] [4 5] 
    [4 6] [4 7] [5 6] [5 7] [6 7]) 

potem po prostu korzystać z tych par w doseq jakiegokolwiek skutku ubocznego:

(let [v [1 2 3 4 5 6 7] 
     pairs (fn [items-seq] 
       (mapcat #(map (partial vector (first %)) (rest %)) 
         (take-while not-empty (iterate rest items-seq))))] 
    (doseq [[i1 i2] (pairs v)] (println i1 i2))) 

zmiana: następującą odpowiedź @ dg123 za. to jest ładne, ale można zrobić to nawet lepiej, używając doseq funkcje 's i for Like rozpad i osłony:

(let [v [1 2 3 4 5 6 7]] 
    (doseq [[x & xs] (iterate rest v) 
      :while xs 
      y xs] 
    (println "x:" x "y:" y))) 

iterację ogonów kolekcji, ale należy pamiętać, że iterate produkuje nieskończona coll:

user> (take 10 (iterate rest [1 2 3 4 5 6 7])) 
([1 2 3 4 5 6 7] (2 3 4 5 6 7) (3 4 5 6 7) 
(4 5 6 7) (5 6 7) (6 7) (7)()()()) 

, więc musisz go w jakiś sposób ograniczyć, aby uwzględnić tylko puste kolekcje. postać rozpad [x & xs] rozdziela argumentu pierwszego param i sekwencję params spoczynku:

user> (let [[x & xs] [1 2 3 4 5 6]] 
     (println x xs)) 
1 (2 3 4 5 6) 
nil 

i gdy oprawiony zbiór pusty, posiada jeden elemencie, xs będzie nil:

user> (let [[x & xs] [1]] 
     (println x xs)) 
1 nil 
nil 

więc po prostu skorzystaj z tej funkcji, korzystając ze straży :while w zrozumieniu listy.

w końcu po prostu skonstruować pary (czy jakiś efekt uboczny w tym przypadku) dla x i każdy element w xs

+1

Powinieneś zamienić '(v i)' na '(nth v i)' (gdy 'v' nie jest wektorem). – user5187212

2

Jak na temat korzystania map vector i iterate:

user=> (def l [1 2 3 4 5]) 
#'user/l 
user=> (map vector l (iterate rest (drop 1 l))) 
([1 (2 3 4 5)] [2 (3 4 5)] [3 (4 5)] [4 (5)] [5()]) 

który wytwarza leniwy sekwencję wartości każdego indeksu i, a następnie wszystkie jej wartości j.

Można następnie iteracyjne nad wszystkich par wartości, które wymagają korzystania for tak:

user=> (for [[i js] (map vector l (iterate rest (drop 1 l))) 
      j js] 
     [i j]) 
([1 2] [1 3] [1 4] [1 5] [2 3] [2 4] [2 5] [3 4] [3 5] [4 5]) 

Zastosowanie doseq jeśli chcesz wykonać IO zamiast produkować leniwe sekwencję:

user=> (doseq [[i js] (map vector l (iterate rest (drop 1 l))) 
       j js] 
     (println (str "i: " i " j: " j))) 
i: 1 j: 2 
i: 1 j: 3 
i: 1 j: 4 
i: 1 j: 5 
i: 2 j: 3 
i: 2 j: 4 
i: 2 j: 5 
i: 3 j: 4 
i: 3 j: 5 
i: 4 j: 5 
nil 
Powiązane problemy