2011-08-17 19 views
9

Tôi tự hỏi nếu tôi thiếu một cái gì đó cơ bản liên quan đến thao tác vector. Hãy nói rằng tôi có như sau:Làm cách nào để sửa đổi một phần của vectơ trong Clojure?

(def xs [9 10 11 12 13]) 
(def idx [0 2]) 
(def values [1 3]) 

Nếu tôi muốn trở về vector [1 10 3 12 13] trong Matlab, tôi sẽ viết xs(idx) = values. Trong Clojure, có một cách nguyên thủy để đạt được điều này? Hiện tại, tôi đang sử dụng chức năng sau:

(defn xinto [seq idx val] 
    (apply assoc seq (interleave idx val))) 

Cảm ơn.

+0

Tôi không thể cung cấp mã nào ngoài các đề xuất đã cho. 'assoc' _is_ nguyên thủy thích hợp nhưng nó muốn các chỉ mục và các giá trị được truyền riêng lẻ như bạn đã thấy. Bạn có thể xây dựng một chuỗi các cặp giá trị chỉ mục như bạn làm và sử dụng 'apply' hoặc đệ quy làm assoc bằng cách sử dụng' reduce' như được gợi ý bởi amalloy và mikera. Theo mặc định, phiên bản multi-value của assoc vẫn được đệ quy. Tôi sẽ xem xét các tùy chọn 'reduce' thành ngữ hơn. –

+0

Tôi nghĩ giải pháp của bạn là khá tốt nhất. –

+2

'áp dụng assoc' và' xen kẽ' có lẽ là lựa chọn tốt nhất khi tất cả những gì bạn muốn làm là đặt cụ thể chỉ mục mà không quan tâm đến giá trị trước đó của nó. Hầu hết thời gian tôi nghi ngờ bạn sẽ muốn làm một cái gì đó phức tạp hơn, và sau đó "lừa" này sẽ không làm việc ở tất cả; đó là lý do tại sao tôi đề nghị sử dụng 'reduce', tổng quát hơn. – amalloy

Trả lời

8

Hơi khó xử vì bạn đã chia nhỏ idxvalues thành hai seq, khi chúng là khái niệm bản đồ chỉ mục về giá trị. Vì vậy, nếu bạn sẽ cho phép tôi một chút thay đổi sáng tạo của định dạng dữ liệu của bạn:

(def x [9 10 11 12 13]) 
(def changes {0 1, 2 3}) 

(defn xinto [v changes] 
    (reduce (fn [acc [k v]] 
      (assoc acc k v)) 
      v 
      changes)) 

(xinto x changes) ;; gets the result you want 

Nếu bạn tạo idxvalues theo một cách kỳ lạ rằng nó không thuận tiện để nhóm chúng lại với nhau, bạn có thể nhóm chúng sau này với (map list idx values) và sau đó sử dụng triển khai xinto của tôi với điều đó.

+0

Hãy xem xét sử dụng 'transient',' assoc! ', Và' persistent! 'Ở đây. – seh

+3

@seh Uh, tôi đoán bạn có thể làm điều đó, nhưng nó hầu như không có giá trị nỗ lực. Nếu một trong hai vector ban đầu hoặc tập hợp các thay đổi để thực hiện là nhỏ, thì thời gian cần thiết để chuyển đổi sang/từ một thoáng qua sẽ lớn hơn lợi ích của việc sử dụng một. – amalloy

+0

hoặc (giá trị idmap zipmap) thay vì (giá trị idx danh sách bản đồ) – zmila

2

Không thể tìm thấy nội dung nào tốt hơn.

Trong các chức năng chuỗi lõi có replace, nhưng nó hoạt động trên các giá trị, không phải trên bàn phím. Vì vậy,

(replace {9 2} x) 

Would return

[2 10 11 12 13] 

Nếu bạn có kế hoạch để làm toán những thứ liên quan trong Clojure, tôi cũng đề nghị bạn có một cái nhìn tại Incanter. Nó có rất nhiều API để thao tác dữ liệu toán học.

3

tôi có lẽ muốn sử dụng reduce cho việc này:

(reduce 
    (fn [old [i v]] (assoc old i v)) 
    x 
    (map vector idx values)) 

Tuy nhiên, nếu bạn thực sự muốn làm điều này rất nhiều (Matlab-style) sau đó tôi muốn khuyên bạn nên tạo một số macro helper/chức năng để tạo ra một số loại DSL cho thao tác vectơ.

+0

Tôi đã cố gắng làm theo mã ví dụ nhưng dường như nó bị thiếu vectơ gốc 'x'. Tôi đã chỉnh sửa ví dụ này thành dạng ba đối số để giảm bớt sự rõ ràng. –

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