2012-11-05 30 views
7

Để hiểu rõ hơn về mapcat tôi lấy một ví dụ:mapcat sử dụng bản đồ và concat

user> (mapcat #(list % %) [1 2 3]) 
(1 1 2 2 3 3) 

Và cố gắng để tái tạo những gì doc mô tả sử dụng, mục đích, đồconcat:

user> (doc mapcat) 
clojure.core/mapcat 
([f & colls]) 
    Returns the result of applying concat to the result of applying map 
    to f and colls. Thus function f should return a collection. 

Bằng cách này:

user> (concat (map #(list % %) [1 2 3])) 
((1 1) (2 2) (3 3)) 

Tuy nhiên, bạn có thể thấy nó không hoạt động. Tuy nhiên tôi có thể sử dụng giảm như thế này nhưng không biết nếu đó là đúng:

user> (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3])) 
(1 1 2 2 3 3) 

Các công trình trên nhưng tôi không biết nếu đó là một cách chính xác để tái tạo, sử dụng đồconcat, những gì mapcat.

Về cơ bản, tôi muốn hiểu về Mapcat hoạt động dưới mui xe.

Điều gì đang xảy ra và làm cách nào tôi có thể truy cập nguồn của Mapcat? (Tôi đang sử dụng Emacs + nrepl)

+1

Sử dụng 'apply' có lẽ tốt hơn' reduce' ở đây vì 'reduce' sẽ thực hiện' concat' cho mỗi cặp đối số.Vì 'concat' là lười, khi các giá trị thực sự bị ép buộc bạn có thể kết thúc với một ngăn xếp cuộc gọi sâu _really_, có thể dẫn đến tràn ngăn xếp. [Đây là một ví dụ đơn giản.] (Https://www.refheap.com/paste/6409) – DaoWen

+2

Chỉ cần một mẹo - trong việc thực hiện của bạn với 'reduce', không cần phải quấn' concat' trong một hàm ẩn danh. Điều này cũng sẽ làm việc: '(giảm concat (map ...))' và là thích hợp hơn vì nó xử lý tốt hơn trường hợp của đầu vào rỗng. – Alex

Trả lời

6
user=> (source mapcat) 
(defn mapcat 
    "Returns the result of applying concat to the result of applying map 
    to f and colls. Thus function f should return a collection." 
    {:added "1.0"} 
    [f & colls] 
    (apply concat (apply map f colls))) 
nil 
user=> 

Lý do reduce cũng làm việc là bởi vì nó là một cách hiệu quả:

(concat (concat '(1 1) '(2 2)) '(3 3)) 

apply, như được sử dụng trong mã nguồn, mở rộng để:

(concat '(1 1) '(2 2) '(3 3)) 

Trong nỗ lực ban đầu của bạn với concat:

user=> (map #(list % %) [1 2 3]) 
    ((1 1) (2 2) (3 3)) 
    user=> (concat (list '(1 1) '(2 2) '(3 3))) 
    ((1 1) (2 2) (3 3)) 
    user=> (concat [1]) 
    (1) 

Bạn có thể thấy rằng nếu bạn gọi concat với một đối số duy nhất, nó sẽ trả về đối số đó.

+1

(áp dụng concat (áp dụng bản đồ f colls)) trông lạ. Tôi không thể có được nó để làm việc. * (Áp dụng concat (bản đồ f colls)) * làm việc cho tôi, nhưng tôi không hiểu việc sử dụng đôi * áp dụng *. Ví dụ * (áp dụng concat (áp dụng bản đồ # (danh sách%%) [1 2])) * không hoạt động !? –

+0

Áp dụng muốn có một danh sách các thông số để pháo đài chính xác cho ví dụ của bạn chỉ với 1 tham số sẽ là (áp dụng concat (áp dụng bản đồ # (danh sách%%) [[1 2]])) – mikkom

2

concat là hàm variadic tức là nó có thể lấy n tham số trong đó mỗi thông số là một chuỗi giá trị tức là chữ ký trở thành (defn concat [& lst]]). Trong khi trong ví dụ của bạn, bạn đang gọi concat với một đối số giả định rằng concat lấy một seq của seq các giá trị được nối và đó là lý do tại sao bạn nhận được kết quả tức là danh sách cùng danh sách được trả về.

(apply concat(apply map #(list % %) [1 2])) sẽ không hoạt động.

(apply map #(list % %) [[1 2]]) hoặc (apply map #(list % %) [1 2] []) sẽ hoạt động.

Điều này là do áp dụng dự kiến ​​tham số cuối cùng là một chuỗi giá trị và mỗi mục trong chuỗi giá trị đó sẽ được chuyển thành tham số cho hàm được áp dụng. Trong trường hợp của bạn áp dụng được không thành công cuộc gọi sẽ mở rộng đến (map #(list % %) 1 2) đó là sai và thông báo lỗi cũng cho thấy nó rằng nó không thể chuyển đổi dài để trình tự như bản đồ cần chuỗi như các tham số.

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