(
ns
^{
:author
"Stuart Halloway"
,
:doc
"Non-core data functions."
}
clojure.data
(
:require
[
clojure.set
:as
set
]
)
)
(
defn-
atom-diff
"Internal helper for diff."
[
a
b
]
(
if
(
=
a
b
)
[
nil
nil
a
]
[
a
b
nil
]
)
)
(
defn-
vectorize
"Convert an associative-by-numeric-index collection into
an equivalent vector, with nil for any missing keys"
[
m
]
(
when
(
seq
m
)
(
reduce
(
fn
[
result
[
k
v
]
]
(
assoc
result
k
v
)
)
(
vec
(
repeat
(
apply
max
(
keys
m
)
)
nil
)
)
m
)
)
)
(
declare
diff
)
(
defprotocol
^{
:added
"1.3"
}
EqualityPartition
"Implementation detail. Subject to change."
(
^{
:added
"1.3"
}
equality-partition
[
x
]
"Implementation detail. Subject to change."
)
)
(
defprotocol
^{
:added
"1.3"
}
Diff
"Implementation detail. Subject to change."
(
^{
:added
"1.3"
}
diff-similar
[
a
b
]
"Implementation detail. Subject to change."
)
)
(
extend
nil
Diff
{
:diff-similar
atom-diff
}
)
(
extend
Object
Diff
{
:diff-similar
atom-diff
}
EqualityPartition
{
:equality-partition
(
fn
[
x
]
(
if
(
..
x
getClass
isArray
)
:sequential
:atom
)
)
}
)
(
defn-
diff-associative
"Diff associative things a and b, comparing only keys in ks."
[
a
b
ks
]
(
reduce
(
fn
[
diff1
diff2
]
(
map
merge
diff1
diff2
)
)
[
nil
nil
nil
]
(
map
(
fn
[
k
]
(
map
#(
when
%
{
k
%
}
)
(
diff
(
get
a
k
)
(
get
b
k
)
)
)
)
ks
)
)
)
(
extend-protocol
EqualityPartition
nil
(
equality-partition
[
x
]
:atom
)
java.util.Set
(
equality-partition
[
x
]
:set
)
java.util.List
(
equality-partition
[
x
]
:sequential
)
java.util.Map
(
equality-partition
[
x
]
:map
)
)
(
extend-protocol
Diff
java.util.Set
(
diff-similar
[
a
b
]
[
(
not-empty
(
set/difference
a
b
)
)
(
not-empty
(
set/difference
b
a
)
)
(
not-empty
(
set/intersection
a
b
)
)
]
)
java.util.List
(
diff-similar
[
a
b
]
(
vec
(
map
vectorize
(
diff-associative
(
if
(
vector?
a
)
a
(
vec
a
)
)
(
if
(
vector?
b
)
b
(
vec
b
)
)
(
range
(
max
(
count
a
)
(
count
b
)
)
)
)
)
)
)
java.util.Map
(
diff-similar
[
a
b
]
(
diff-associative
a
b
(
set/union
(
keys
a
)
(
keys
b
)
)
)
)
)
(
defn
diff
"Recursively compares a and b, returning a tuple of
[things-only-in-a things-only-in-b things-in-both].
Comparison rules:
* Maps are subdiffed where keys match and values differ.
* Sets are never subdiffed.
* All sequential things are treated as associative collections
by their indexes, with results returned as vectors.
* Everything else (including strings!) is treated as
an atom and compared for equality."
{
:added
"1.3"
}
[
a
b
]
(
if
(
=
(
equality-partition
a
)
(
equality-partition
b
)
)
(
diff-similar
a
b
)
(
atom-diff
a
b
)
)
)