2010-07-08 34 views
43

Câu hỏi mới, nhưng tôi thực sự không hiểu tại sao có quá nhiều hoạt động để xây dựng bản đồ bằng clojure.Tại sao có quá nhiều chức năng xây dựng bản đồ trong clojure?

Bạn có conj, assocmerge, nhưng dường như chúng có nhiều hay ít làm điều tương tự?

(assoc {:a 1 :b 2} :c 3) 
(conj {:a 1 :b 2} {:c 3}) 
(merge {:a 1 :b 2} {:c 3}) 

Điều gì thực sự khác biệt và tại sao tất cả các phương pháp này được yêu cầu khi chúng làm nhiều hơn hoặc ít hơn cùng một thứ?

+6

Cũng có '(thành {: a 1: b 2} {: c 3})' – VitoshKa

Trả lời

47

assocconj cư xử rất khác nhau cho các cấu trúc dữ liệu khác:

user=> (assoc [1 2 3 4] 1 5) 
[1 5 3 4] 
user=> (conj [1 2 3 4] 1 5) 
[1 2 3 4 1 5] 

Nếu bạn đang viết một hàm có thể xử lý nhiều loại bộ sưu tập, sau đó lựa chọn của bạn sẽ làm cho một sự khác biệt lớn.

Xử lý merge làm chức năng chỉ bản đồ (tương tự như conj cho các bộ sưu tập khác).

Ý kiến ​​của tôi:

  • assoc - sử dụng khi bạn đang 'thay đổi' cặp khóa/giá trị hiện có
  • conj - sử dụng khi bạn đang 'thêm' cặp khóa/giá trị mới
  • hợp nhất - sử dụng khi bạn kết hợp hai hoặc nhiều bản đồ
+4

'hợp nhất' có một số lượng bản đồ trọng yếu và hợp nhất chúng, không chỉ hai. – ponzao

+1

Điểm tốt. Thay đổi từ ngữ của tôi. – dbyrne

+0

Không có prob, +1 cho một câu trả lời tốt. – ponzao

6

Vì bản đồ là cấu trúc dữ liệu phổ biến ở Clojure, nên có nhiều công cụ để thao tác chúng. Các chức năng khác nhau là tất cả các cú pháp thuận tiện trong các trường hợp hơi khác nhau.

mất cá nhân của tôi về chức năng cụ thể mà bạn đề cập đến:

  • tôi sử dụng assoc để thêm một giá trị duy nhất để một bản đồ cho một chìa khóa và giá trị so
  • tôi sử dụng merge để kết hợp hai bản đồ hoặc thêm nhiều mục mới cùng một lúc
  • Tôi thường không sử dụng conj với bản đồ hoàn toàn vì tôi liên kết nó với danh sách
+2

Tôi nghĩ rằng cách tiếp cận thành ngữ sẽ là sử dụng chức năng nào phù hợp với biểu mẫu trong đó các mục mới sẽ được thêm vào bản đồ ban đầu trở nên có sẵn; nếu nó là bản đồ, hãy sử dụng 'merge', nếu như một loạt các khóa và giá trị không được tập hợp trong một bộ sưu tập, hãy sử dụng' assoc' vv. Điều tôi thực sự muốn chỉ ra, đó là 'conj' là * the * universal Chức năng xây dựng cấu trúc dữ liệu Clojure - bạn không thể giữ nó trong ngăn kéo danh sách. –

+0

@Malal có thể bạn đúng - nhưng vì một lý do nào đó tôi có một sự ngờ vực về chức năng làm những điều rất khác biệt về kiểu đầu vào khác nhau mà không cảnh báo :-) – mikera

+4

Tôi cho rằng 'conj' ** không ** thực hiện các hoạt động tương đương ngữ nghĩa trên các loại đầu vào khác nhau. ;) – dbyrne

21

Trên thực tế, các chức năng này hoạt động khá khác nhau khi được sử dụng với bản đồ.

  1. conj:

    Thứ nhất, (conj {:a 1 :b 2} :c 3) dụ từ các văn bản câu hỏi không làm việc ở tất cả (không phải với 1.1 cũng không phải với 1,2; IllegalArgumentException được ném). Chỉ có một số loại có thể là conj ed lên bản đồ, cụ thể là vectơ hai phần tử, clojure.lang.MapEntry s (về cơ bản tương đương với vectơ hai phần tử) và bản đồ.

    Lưu ý rằng seq của bản đồ bao gồm một bó MapEntry s. Vì vậy, bạn có thể làm ví dụ:

    (into a-map (filter a-predicate another-map)) 
    

    (lưu ý rằng into sử dụng conj - hoặc conj!, khi có thể - trong nội bộ). Không phải merge cũng không assoc cho phép bạn làm điều đó.

  2. merge:

    Đây là gần như chính xác tương đương với conj, nhưng nó sẽ thay thế nil đối số của nó với {} - bản đồ băm rỗng - và do đó sẽ trả về một bản đồ khi là người đầu tiên "bản đồ" trong chuỗi xảy ra là nil.

    (apply conj [nil {:a 1} {:b 2}]) 
    ; => ({:b 2} {:a 1}) ; clojure.lang.PersistentList 
    (apply merge [nil {:a 1} {:b 2}]) 
    ; => {:a 1 :b 2} ; clojure.lang.PersistentArrayMap 
    

    Lưu ý không có gì (ngoại trừ docstring ...) để ngăn lập trình viên sử dụng merge cùng với các loại bộ sưu tập khác. Nếu một người làm điều đó, sự kỳ quặc xảy ra; không được khuyến khích.

  3. assoc:

    Một lần nữa, ví dụ từ các văn bản câu hỏi - (assoc {:a 1 :b 2} {:c 3}) - sẽ không hoạt động; thay vào đó, nó sẽ ném một IllegalArgumentException. assoc lấy đối số bản đồ theo sau bởi một số chẵn đối số - các đối số ở vị trí lẻ (giả sử bản đồ ở vị trí 0) là các khóa, các vị trí ở vị trí chẵn là các giá trị. Tôi thấy rằng tôi assoc những thứ trên bản đồ thường xuyên hơn tôi conj, mặc dù khi tôi conj, assoc sẽ cảm thấy cồng kềnh. ;-)

  4. merge-with:

    Vì lợi ích của sự hoàn chỉnh, đây là chức năng cơ bản chính thức đối phó với bản đồ. Tôi thấy nó cực kỳ hữu ích. Nó hoạt động như docstring cho biết; đây là ví dụ:

    (merge-with + {:a 1} {:a 3} {:a 5}) 
    ; => {:a 9} 
    

    Lưu ý rằng nếu bản đồ chứa khóa "mới" chưa xuất hiện trong bất kỳ bản đồ nào ở bên trái, chức năng hợp nhất sẽ không được gọi. Điều này đôi khi bực bội, nhưng trong 1.2 một thông minh reify có thể cung cấp một bản đồ với không phải là nil "giá trị mặc định".

+0

Để minh họa điểm cuối cùng trên 'merge-with', tôi đã chuẩn bị Gist sau đây: http://gist.github.com/468332 –

+0

Cảm ơn bạn đã giải thích. Như bạn thấy tôi đã có một lỗi đánh máy và chuyển đối số thứ hai giữa conj và assoc. – grm

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