Skip to content

Commit 0645ad9

Browse files
committed
Issue #4: Fixed TreeMap.split and added splitLookup
1 parent 5147cdf commit 0645ad9

3 files changed

Lines changed: 95 additions & 14 deletions

File tree

core/src/main/java/fj/Equal.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,10 @@ public static <A> Equal<Set<A>> setEqual(final Equal<A> e) {
522522
return equal(curry((Set<A> a, Set<A> b) -> streamEqual(e).eq(a.toStream(), b.toStream())));
523523
}
524524

525+
public static <K, V> Equal<TreeMap<K, V>> treeMapEqual(Equal<K> k, Equal<V> v) {
526+
return equal(t1 -> t2 -> Equal.streamEqual(p2Equal(k, v)).eq(t1.toStream(), t2.toStream()));
527+
}
528+
525529
public static <A, B> Equal<Writer<A, B>> writerEqual(Equal<A> eq1, Equal<B> eq2) {
526530
return equal(w1 -> w2 -> p2Equal(eq1, eq2).eq(w1.run(), w2.run()));
527531
}

core/src/main/java/fj/data/TreeMap.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ public Map<K, V> toMutableMap() {
169169
return m;
170170
}
171171

172+
public Stream<P2<K, V>> toStream() {
173+
return Stream.iteratorStream(iterator());
174+
}
172175
/**
173176
* An immutable projection of the given mutable map.
174177
*
@@ -234,13 +237,50 @@ public TreeMap<K, V> update(final K k, final F<V, V> f, final V v) {
234237
* key in this map, all the elements in the second set are mapped to keys greater than the given key,
235238
* and the optional value is the value associated with the given key if present, otherwise None.
236239
*/
237-
public P3<Set<V>, Option<V>, Set<V>> split(final K k) {
238-
final F<Set<P2<K, Option<V>>>, Set<V>> getSome = F1Functions.mapSet(F1Functions.o(Option.<V>fromSome(), P2.<K, Option<V>>__2())
239-
, tree.ord().comap(F1Functions.o(P.<K, Option<V>>p2().f(k), Option.<V>some_())));
240+
public P3<Set<V>, Option<V>, Set<V>> split(Ord<V> ord, final K k) {
241+
final F<Set<P2<K, Option<V>>>, Set<V>> getSome = F1Functions.mapSet(F1Functions.o(Option.<V>fromSome(), P2.<K, Option<V>>__2()), ord);
240242
return tree.split(p(k, Option.<V>none())).map1(getSome).map3(getSome)
241243
.map2(F1Functions.o(Option.<V>join(), F1Functions.mapOption(P2.<K, Option<V>>__2())));
242244
}
243245

246+
/**
247+
* Internal construction of a TreeMap from the given set.
248+
* @param ord An order for the keys of the tree map.
249+
* @param s The elements to construct the tree map with.
250+
* @return a TreeMap with the given elements.
251+
*/
252+
private static <K, V> TreeMap<K, V> map(Ord<K> ord, Set<P2<K, Option<V>>> s) {
253+
TreeMap<K, V> empty = TreeMap.<K, V>empty(ord);
254+
TreeMap<K, V> tree = s.toList().foldLeft((tm, p2) -> {
255+
Option<V> opt = p2._2();
256+
if (opt.isSome()) {
257+
return tm.set(p2._1(), opt.some());
258+
}
259+
return tm;
260+
}, empty);
261+
return tree;
262+
}
263+
264+
/**
265+
* Splits this TreeMap at the given key. Returns a triple of:
266+
* <ul>
267+
* <li>A tree map containing all the values of this map associated with keys less than the given key.</li>
268+
* <li>An option of a value mapped to the given key, if it exists in this map, otherwise None.
269+
* <li>A tree map containing all the values of this map associated with keys greater than the given key.</li>
270+
* </ul>
271+
*
272+
* @param k A key at which to split this map.
273+
* @return Two tree maps and an optional value, where all keys in the first tree map are mapped
274+
* to keys less than the given key in this map, all the keys in the second tree map are mapped
275+
* to keys greater than the given key, and the optional value is the value associated with the
276+
* given key if present, otherwise None.
277+
*/
278+
public P3<TreeMap<K, V>, Option<V>, TreeMap<K, V>> splitLookup(final K k) {
279+
P3<Set<P2<K, Option<V>>>, Option<P2<K, Option<V>>>, Set<P2<K, Option<V>>>> p3 = tree.split(P.p(k, get(k)));
280+
Ord<K> o = tree.ord().<K>comap(k2 -> P.p(k2, Option.<V>none()));
281+
return P.p(map(o, p3._1()), get(k), map(o, p3._3()));
282+
}
283+
244284
/**
245285
* Maps the given function across the values of this TreeMap.
246286
*

core/src/test/java/fj/data/TreeMapTest.java

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,75 @@
44
import fj.Ord;
55
import fj.P3;
66
import fj.Show;
7+
import fj.P;
78
import org.junit.Assert;
89
import org.junit.Test;
910

11+
import static fj.data.Option.some;
12+
import static org.junit.Assert.assertTrue;
13+
1014
/**
1115
* Created by MarkPerry on 11/01/2015.
1216
*/
1317
public class TreeMapTest {
1418

1519
@Test
1620
public void split() {
21+
// do the split
1722
int pivot = 4;
18-
List<Integer> l = List.range(1, 6);
23+
int max = 5;
24+
List<Integer> l = List.range(1, max + 1);
1925
TreeMap<Integer, String> m2 = TreeMap.map(Ord.intOrd, l.zip(l.map(i -> i.toString())));
20-
P3<Set<String>, Option<String>, Set<String>> p = m2.split(pivot);
26+
P3<Set<String>, Option<String>, Set<String>> p = m2.split(Ord.stringOrd, pivot);
27+
28+
// print debug info
2129
Show<TreeMap<Integer, String>> st = Show.treeMapShow(Show.intShow, Show.stringShow);
2230
Show<Set<String>> ss = Show.setShow(Show.stringShow);
2331
Show<Option<String>> so = Show.optionShow(Show.stringShow);
2432
Show<P3<Set<String>, Option<String>, Set<String>>> sp3 = Show.p3Show(ss, so, ss);
33+
if (true) {
34+
st.println(m2);
35+
sp3.println(p);
36+
}
2537

26-
st.println(m2);
27-
sp3.println(p);
28-
29-
Equal<Set<String>> eq = Equal.setEqual(Equal.stringEqual);
30-
Set<String> left = toSetString(List.list(1, 2, 3));
31-
Set<String> right = toSetString(List.list(5));
32-
Assert.assertTrue("Left side of split unexpected", eq.eq(left, p._1()));
33-
Assert.assertTrue(eq.eq(right, p._1()));
34-
Assert.assertTrue(Equal.optionEqual(Equal.stringEqual).eq(p._2(), Option.some(Integer.toString(pivot))));
38+
// assert equals
39+
Equal<Set<String>> seq = Equal.setEqual(Equal.stringEqual);
40+
Set<String> left = toSetString(List.range(1, pivot));
41+
Set<String> right = toSetString(List.range(pivot + 1, max + 1));
42+
P3<Set<String>, Option<String>, Set<String>> expected = P.p(left, some(Integer.toString(pivot)), right);
43+
assertTrue(Equal.p3Equal(seq, Equal.optionEqual(Equal.stringEqual), seq).eq(p, expected));
3544
}
3645

3746
private static Set<String> toSetString(List<Integer> list) {
3847
return Set.set(Ord.stringOrd, list.map(i -> i.toString()));
3948
}
4049

50+
@Test
51+
public void splitLookup() {
52+
// do the split
53+
int pivot = 4;
54+
int max = 5;
55+
List<Integer> l = List.range(1, max + 1);
56+
TreeMap<Integer, String> m2 = TreeMap.map(Ord.intOrd, l.zip(l.map(i -> i.toString())));
57+
P3<TreeMap<Integer, String>, Option<String>, TreeMap<Integer, String>> p3 = m2.splitLookup(pivot);
58+
59+
// create expected output
60+
List<Integer> leftList = List.range(1, pivot);
61+
TreeMap<Integer, String> leftMap = TreeMap.map(Ord.intOrd, leftList.zip(leftList.map(i -> i.toString())));
62+
List<Integer> rightList = List.range(pivot + 1, max + 1);
63+
TreeMap<Integer, String> rightMap = TreeMap.map(Ord.intOrd, rightList.zip(rightList.map(i -> i.toString())));
64+
65+
// debug info
66+
if (true) {
67+
Show<TreeMap<Integer, String>> st = Show.treeMapShow(Show.intShow, Show.stringShow);
68+
Show<P3<TreeMap<Integer, String>, Option<String>, TreeMap<Integer, String>>> sp3 = Show.p3Show(st, Show.optionShow(Show.stringShow), st);
69+
sp3.println(p3);
70+
}
71+
72+
// do the assert
73+
Equal<TreeMap<Integer, String>> tme = Equal.treeMapEqual(Equal.intEqual, Equal.stringEqual);
74+
Equal<P3<TreeMap<Integer, String>, Option<String>, TreeMap<Integer, String>>> eq = Equal.p3Equal(tme, Equal.optionEqual(Equal.stringEqual), tme);
75+
assertTrue(eq.eq(p3, P.p(leftMap, some(Integer.toString(pivot)), rightMap)));
76+
}
77+
4178
}

0 commit comments

Comments
 (0)