2011-09-29 38 views
7

một này đã được làm phiền tôi trong một thời gian bây giờ, Làm sao chúng ta nên lưu trữ một giá trị trong một tập bản đồ hoặc trong một vòng lặp for?clojure vòng lặp for, lưu trữ các giá trị trong một tập bản đồ hoặc

(let [s #{}] 
    (for [ i (range 10) 
      j (range 10) ] 
     (into s [i j]))) 

tôi biết điều này sẽ không làm việc, nhưng tôi muốn có một chức năng tương tự như sau, nơi tập cuối cùng sẽ chứa [0 0] [0 1] ... [0 9] [1 0] .. . [9 9]

Cảm ơn

+0

Cảm ơn tất cả, vì các câu trả lời. – KaKa

Trả lời

13

Nếu tôi hiểu câu hỏi của bạn một cách chính xác bạn cần bật biểu hiện của bạn trong ra ngoài:

(let [s #{}] 
    (into s (for [i (range 10) 
       j (range 10)] 
      [i j]))) 

Những điều cần thực hiện ở đây là rằng for trả về một giá trị (một chuỗi lười) không giống như các vòng lặp trong các ngôn ngữ bắt buộc hơn như Java và C.

0

clojure có một số hệ thống tuyệt vời để quản lý trạng thái có thể thay đổi. trong trường hợp này bạn có thể muốn một atom chứa một tập

lựa chọn khác của bạn là:

  • một ref nếu có nhiều hơn một sự thay đổi cần phải thực hiện (phối hợp đề nhiều)
  • một var nếu điều này sẽ đơn luồng (một var có thể làm việc giống như ở đây cũng như một nguyên tử)
  • một agent nếu bạn muốn thiết lập giá trị của s không đồng bộ

tất nhiên for trả về một chuỗi đã vì vậy bạn chỉ có thể muốn

(into #{} (for [ i (range 10) 
        j (range 10) ] 
      [i j])) 
+0

Đoạn mã đầu tiên ở đây không có ý nghĩa gì, theo như tôi có thể nói? Nó không phải là một cách hợp lệ để sử dụng 'swap! ', Và như bạn sau đó đề cập đến nó không phải là một ý tưởng tốt anyway. – amalloy

+0

snipit đầu tiên đã không thực sự là điểm của câu trả lời anyway vì vậy tôi chỉ cần loại bỏ nó. đặt ra với thử nghiệm * tisk tisk * –

6

Đây có phải là những gì bạn muốn không?

(into #{} (for [i (range 10) j (range 10)] 
    [i j])) 
;-> #{[2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [1 0] 
;  [2 2] [3 3] [4 4] [5 5] [6 6]... 

Và nếu bạn chỉ muốn trong danh sách là một tập hợp:

(set (for [i (range 10) j (range 10)] 
    [i j]))  

Bạn sẽ kết thúc với một tập hợp các cặp.

5

chung khi bạn muốn quay trở lại một bộ hoặc một bản đồ hoặc khác 'giá trị duy nhất' đó không phải là một seq từ một 'lặp lại' hoạt động tổng quát trên seq, sử dụng reduce là nhiều thành ngữ/đơn giản hơn loop/recur, và for luôn trả về seq (không phải là tập hợp hoặc bản đồ).

(reduce conj #{} (for [i (range 10) j (range 10)] [i j])) 

lưu ý rằng (cho ..) ở đây chỉ được sử dụng để sản xuất một seq chứa tất cả các giá trị để biên dịch vào kết quả duy nhất thiết. Hoặc, ví dụ:

(reduce + 0 (range 100)) 
=> 4950 
0

Tôi nghĩ bạn cũng có thể sử dụng một số cấu trúc dữ liệu thoáng qua trong trường hợp này.

(let [s (transient #{})] 
(for [ i (range 10) 
     j (range 10) ] 
    (assoc! s i j))) 
(persistent! s) 

Chỉ là mẫu mã, chưa được thử nghiệm.

+1

Điều này không chính xác. Từ [tài liệu cho transients] (http://clojure.org/transients): "Lưu ý đặc biệt rằng transients không được thiết kế để được bashing tại chỗ. Bạn phải nắm bắt và sử dụng giá trị trả về trong cuộc gọi tiếp theo. cách này, chúng hỗ trợ cấu trúc mã giống như mã liên tục chức năng mà chúng thay thế ". – Jonas

Các vấn đề liên quan