merge dense with sparse now works
Not yet sure I'm right about the semantics of sparse-with-dense: are nils in a dense array first class values?
This commit is contained in:
parent
59fb5529aa
commit
1aa3173dc9
|
@ -210,7 +210,7 @@ e.g.
|
|||
|
||||
### extract-from-dense
|
||||
|
||||
Note that the above example returns the default axis sequence {i0, i1, i2...};
|
||||
Note that the above example returns the default axis sequence `{i0, i1, i2...}`;
|
||||
extracting from a sparse array will always retain the axes of the array
|
||||
extracted from. Dense arrays, obviously, do not have explicit axes.
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
(defn sparse-array?
|
||||
"`true` if `x` is a sparse array conforming to the conventions established
|
||||
by this library, else `false`."
|
||||
;; TODO: sparse-array? should not throw exceptions even when
|
||||
;; *safe-sparse-operations* is true, since we may use to test
|
||||
;; whether an object is a sparse array. The place to throw the exceptions
|
||||
;; (if required) is after it has failed.
|
||||
([x]
|
||||
(apply
|
||||
sparse-array?
|
||||
|
@ -171,6 +175,31 @@
|
|||
:else
|
||||
(unsafe-get array coordinates)))
|
||||
|
||||
|
||||
(defn dense-dimensions
|
||||
"How many usable dimensions (represented as vectors) does the dense array
|
||||
`x` have?"
|
||||
[x]
|
||||
(if
|
||||
(vector? x)
|
||||
(if
|
||||
(every? vector? x)
|
||||
(inc (apply min (map dense-dimensions x)))
|
||||
;; `min` is right here, not `max`, because otherwise
|
||||
;; we will get malformed arrays. Be liberal with what you
|
||||
;; consume, conservative with what you return!
|
||||
1)
|
||||
0))
|
||||
|
||||
(defn dense-array?
|
||||
"Basically, any vector can be considered as a dense array of one dimension.
|
||||
If we're seeking a dense array of more than one dimension, the number of
|
||||
dimensions should be specified as `d`."
|
||||
([x]
|
||||
(vector? x))
|
||||
([x d]
|
||||
(and (vector? x) (< d (dense-dimensions x)))))
|
||||
|
||||
(defn merge-sparse-arrays
|
||||
"Return a sparse array taking values from sparse arrays `a1` and `a2`,
|
||||
but preferring values from `a2` where there is a conflict. `a1` and `a2`
|
||||
|
@ -198,29 +227,55 @@
|
|||
(keys a1)
|
||||
(keys a2))))))))
|
||||
|
||||
(defn dense-dimensions
|
||||
"How many usable dimensions (represented as vectors) does the dense array
|
||||
`x` have?"
|
||||
[x]
|
||||
(if
|
||||
(vector? x)
|
||||
(if
|
||||
(every? vector? x)
|
||||
(inc (apply min (map dense-dimensions x)))
|
||||
;; `min` is right here, not `max`, because otherwise
|
||||
;; we will get malformed arrays. Be liberal with what you
|
||||
;; consume, conservative with what you return!
|
||||
1)
|
||||
0))
|
||||
(defn merge-dense-with-sparse
|
||||
"Merge this dense array `d` with this sparse array `s`, returning a new
|
||||
dense array with the same arity as `d`, preferring values from `s` where
|
||||
there is conflict"
|
||||
[d s]
|
||||
(apply
|
||||
vector
|
||||
(map
|
||||
#(cond
|
||||
(= :data (:content s))
|
||||
(or (s %2) %1)
|
||||
(nil? (s %2))
|
||||
%1
|
||||
:else
|
||||
(merge-dense-with-sparse %1 (s %2)))
|
||||
d
|
||||
(range))))
|
||||
|
||||
(defn dense-array?
|
||||
"Basically, any vector can be considered as a dense array of one dimension.
|
||||
If we're seeking a dense array of more than one dimension, the number of
|
||||
dimensions should be specified as `d`."
|
||||
([x]
|
||||
(vector? x))
|
||||
([x d]
|
||||
(and (vector? x) (< d (dense-dimensions x)))))
|
||||
(defn merge-arrays
|
||||
"Merge two arrays `a1`, `a2`, which may be either dense or sparse but which
|
||||
should have the same number of axes and compatible dimensions, and return a
|
||||
new dense array preferring values from `a2`."
|
||||
[a1 a2]
|
||||
(cond
|
||||
(dense-array? a2)
|
||||
a2 ;; if a2 is dense, no values from a1 will be returned
|
||||
(sparse-array? a1)
|
||||
(cond
|
||||
(sparse-array? a2)
|
||||
(merge-sparse-arrays a1 a2)
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a2})))
|
||||
(dense-array? a1)
|
||||
(cond
|
||||
(sparse-array? a2)
|
||||
(merge-dense-with-sparse a1 a2)
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a2})))
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a1}))))
|
||||
|
||||
(defn dense-to-sparse
|
||||
"Return a sparse array representing the content of the dense array `x`,
|
||||
|
|
|
@ -172,20 +172,30 @@
|
|||
(get (make-sparse-array :x :y :z) 3 4 5 6))))))
|
||||
|
||||
(deftest merge-test
|
||||
(testing "merge, one dimension"
|
||||
(testing "merge, sparse arrays, one dimension"
|
||||
(let
|
||||
[merged (merge-sparse-arrays
|
||||
[merged (merge-arrays
|
||||
(put (make-sparse-array :x) "hello" 3)
|
||||
(put (make-sparse-array :x) "goodbye" 4))]
|
||||
(is (= "hello" (get merged 3)))
|
||||
(is (= "goodbye" (get merged 4)))))
|
||||
(testing "merge, two dimensions"
|
||||
(testing "merge, sparse arrays, two dimensions"
|
||||
(let
|
||||
[merged (merge-sparse-arrays
|
||||
[merged (merge-arrays
|
||||
(put (make-sparse-array :x :y) "hello" 3 4)
|
||||
(put (make-sparse-array :x :y) "goodbye" 4 3))]
|
||||
(is (= "hello" (get merged 3 4)))
|
||||
(is (= "goodbye" (get merged 4 3))))))
|
||||
(is (= "goodbye" (get merged 4 3)))))
|
||||
(testing "merge, dense with sparse, two dimensions")
|
||||
(let [dense [[[nil nil nil][nil nil nil][nil nil nil]]
|
||||
[[nil nil nil][nil nil nil][nil nil nil]]
|
||||
[[nil nil nil][nil nil nil][nil nil nil]]]
|
||||
sparse (put (put (make-sparse-array :x :y :z) "hello" 0 0 0) "goodbye" 2 2 2)
|
||||
expected [[["hello" nil nil] [nil nil nil] [nil nil nil]]
|
||||
[[nil nil nil] [nil nil nil] [nil nil nil]]
|
||||
[[nil nil nil] [nil nil nil] [nil nil "goodbye"]]]
|
||||
actual (merge-arrays dense sparse)]
|
||||
(is (= actual expected))))
|
||||
|
||||
(deftest dense-to-sparse-tests
|
||||
(testing "dense-to-sparse, one dimension"
|
||||
|
|
Loading…
Reference in a new issue