Skip to content

Commit e43e44b

Browse files
authored
Optimized Traversable<>.unzip(Function, Function) (#2662)
* Optimized Traversable<>.unzip(Function, Function) New unzip() method accepts two functions to avoid extensive Tuple creation under the hood. * Removing commented-out line * Changing return type for Traversable<>.unzip(Function, Function) to Tuple2<Iterator<T1>, Iterator<T2>> * Fixing Iterator.unzip(Function, Function) bug * Fixing typo * Minor: unnecessary empty line removed * Minore refinement to AbstractTraversableTest unzip(Function, Function) * Adding Traversable<>.unzip3(Function, Function, Function) * Minor changes to comments, tests re-grouping * Removing Traversable<>.unzip(Function), Traversable<>.unzip3(Function) * IteratorTest.java fix for unzip, unzip3 * Renaming tests for unzip, unzip3 * Java 8 warnings fix * Java 8 warning fix (again) * Return type simplified for Traversable<>.unzip3() to Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> * Minor types adjustment in AbstractTraversableTest.java
1 parent da85b37 commit e43e44b

29 files changed

+80
-564
lines changed

src/main/java/io/vavr/collection/Array.java

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,43 +1448,6 @@ public <U> U transform(Function<? super Array<T>, ? extends U> f) {
14481448
return f.apply(this);
14491449
}
14501450

1451-
@Override
1452-
public <T1, T2> Tuple2<Array<T1>, Array<T2>> unzip(
1453-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
1454-
Objects.requireNonNull(unzipper, "unzipper is null");
1455-
if (isEmpty()) {
1456-
return Tuple.of(empty(), empty());
1457-
} else {
1458-
final Object[] xs = new Object[delegate.length];
1459-
final Object[] ys = new Object[delegate.length];
1460-
for (int i = 0; i < delegate.length; i++) {
1461-
final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(get(i));
1462-
xs[i] = t._1;
1463-
ys[i] = t._2;
1464-
}
1465-
return Tuple.of(wrap(xs), wrap(ys));
1466-
}
1467-
}
1468-
1469-
@Override
1470-
public <T1, T2, T3> Tuple3<Array<T1>, Array<T2>, Array<T3>> unzip3(Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
1471-
Objects.requireNonNull(unzipper, "unzipper is null");
1472-
if (isEmpty()) {
1473-
return Tuple.of(empty(), empty(), empty());
1474-
} else {
1475-
final Object[] xs = new Object[delegate.length];
1476-
final Object[] ys = new Object[delegate.length];
1477-
final Object[] zs = new Object[delegate.length];
1478-
for (int i = 0; i < delegate.length; i++) {
1479-
final Tuple3<? extends T1, ? extends T2, ? extends T3> t = unzipper.apply(get(i));
1480-
xs[i] = t._1;
1481-
ys[i] = t._2;
1482-
zs[i] = t._3;
1483-
}
1484-
return Tuple.of(wrap(xs), wrap(ys), wrap(zs));
1485-
}
1486-
}
1487-
14881451
@Override
14891452
public Array<T> update(int index, T element) {
14901453
if ((index < 0) || (index >= length())) {

src/main/java/io/vavr/collection/BitSet.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -598,24 +598,6 @@ public final BitSet<T> union(Set<? extends T> elements) {
598598
return elements.isEmpty() ? this : addAll(elements);
599599
}
600600

601-
@Override
602-
public final <T1, T2> Tuple2<TreeSet<T1>, TreeSet<T2>> unzip(
603-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
604-
Objects.requireNonNull(unzipper, "unzipper is null");
605-
return iterator().unzip(unzipper).map(i1 -> TreeSet.ofAll(Comparators.naturalComparator(), i1),
606-
i2 -> TreeSet.ofAll(Comparators.naturalComparator(), i2));
607-
}
608-
609-
@Override
610-
public final <T1, T2, T3> Tuple3<TreeSet<T1>, TreeSet<T2>, TreeSet<T3>> unzip3(
611-
Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
612-
Objects.requireNonNull(unzipper, "unzipper is null");
613-
return iterator().unzip3(unzipper).map(
614-
i1 -> TreeSet.ofAll(Comparators.naturalComparator(), i1),
615-
i2 -> TreeSet.ofAll(Comparators.naturalComparator(), i2),
616-
i3 -> TreeSet.ofAll(Comparators.naturalComparator(), i3));
617-
}
618-
619601
@Override
620602
public final <U> TreeSet<Tuple2<T, U>> zip(Iterable<? extends U> that) {
621603
Objects.requireNonNull(that, "that is null");

src/main/java/io/vavr/collection/CharSeq.java

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,34 +1091,6 @@ public <U> U transform(Function<? super CharSeq, ? extends U> f) {
10911091
return f.apply(this);
10921092
}
10931093

1094-
@Override
1095-
public <T1, T2> Tuple2<IndexedSeq<T1>, IndexedSeq<T2>> unzip(Function<? super Character, Tuple2<? extends T1, ? extends T2>> unzipper) {
1096-
Objects.requireNonNull(unzipper, "unzipper is null");
1097-
IndexedSeq<T1> xs = Vector.empty();
1098-
IndexedSeq<T2> ys = Vector.empty();
1099-
for (int i = 0; i < length(); i++) {
1100-
final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(get(i));
1101-
xs = xs.append(t._1);
1102-
ys = ys.append(t._2);
1103-
}
1104-
return Tuple.of(xs, ys);
1105-
}
1106-
1107-
@Override
1108-
public <T1, T2, T3> Tuple3<IndexedSeq<T1>, IndexedSeq<T2>, IndexedSeq<T3>> unzip3(Function<? super Character, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
1109-
Objects.requireNonNull(unzipper, "unzipper is null");
1110-
IndexedSeq<T1> xs = Vector.empty();
1111-
IndexedSeq<T2> ys = Vector.empty();
1112-
IndexedSeq<T3> zs = Vector.empty();
1113-
for (int i = 0; i < length(); i++) {
1114-
final Tuple3<? extends T1, ? extends T2, ? extends T3> t = unzipper.apply(get(i));
1115-
xs = xs.append(t._1);
1116-
ys = ys.append(t._2);
1117-
zs = zs.append(t._3);
1118-
}
1119-
return Tuple.of(xs, ys, zs);
1120-
}
1121-
11221094
@Override
11231095
public CharSeq update(int index, Character element) {
11241096
if ((index < 0) || (index >= length())) {

src/main/java/io/vavr/collection/HashSet.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -888,22 +888,6 @@ public HashSet<T> union(Set<? extends T> elements) {
888888
}
889889
}
890890

891-
@Override
892-
public <T1, T2> Tuple2<HashSet<T1>, HashSet<T2>> unzip(
893-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
894-
Objects.requireNonNull(unzipper, "unzipper is null");
895-
final Tuple2<Iterator<T1>, Iterator<T2>> t = iterator().unzip(unzipper);
896-
return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2));
897-
}
898-
899-
@Override
900-
public <T1, T2, T3> Tuple3<HashSet<T1>, HashSet<T2>, HashSet<T3>> unzip3(
901-
Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
902-
Objects.requireNonNull(unzipper, "unzipper is null");
903-
final Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> t = iterator().unzip3(unzipper);
904-
return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2), HashSet.ofAll(t._3));
905-
}
906-
907891
@Override
908892
public <U> HashSet<Tuple2<T, U>> zip(Iterable<? extends U> that) {
909893
return zipWith(that, Tuple::of);

src/main/java/io/vavr/collection/IndexedSeq.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,6 @@ default boolean startsWith(Iterable<? extends T> that, int offset) {
416416
@Override
417417
IndexedSeq<T> takeRightWhile(Predicate<? super T> predicate);
418418

419-
@Override
420-
<T1, T2> Tuple2<? extends IndexedSeq<T1>, ? extends IndexedSeq<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper);
421-
422-
@Override
423-
<T1, T2, T3> Tuple3<? extends IndexedSeq<T1>, ? extends IndexedSeq<T2>, ? extends IndexedSeq<T3>> unzip3(Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper);
424-
425419
@Override
426420
IndexedSeq<T> update(int index, T element);
427421

src/main/java/io/vavr/collection/Iterator.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,25 +1201,35 @@ public U next() {
12011201

12021202
@Override
12031203
default <T1, T2> Tuple2<Iterator<T1>, Iterator<T2>> unzip(
1204-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
1205-
Objects.requireNonNull(unzipper, "unzipper is null");
1204+
Function<? super T, ? extends T1> unzipper1, Function<? super T, ? extends T2> unzipper2) {
1205+
Objects.requireNonNull(unzipper1, "unzipper1 is null");
1206+
Objects.requireNonNull(unzipper2, "unzipper2 is null");
12061207
if (!hasNext()) {
12071208
return Tuple.of(empty(), empty());
12081209
} else {
1209-
final Stream<Tuple2<? extends T1, ? extends T2>> source = Stream.ofAll(() -> map(unzipper));
1210-
return Tuple.of(source.map(t -> (T1) t._1).iterator(), source.map(t -> (T2) t._2).iterator());
1210+
final Stream<T> stream = Stream.ofAll(() -> this);
1211+
final Iterator<T1> iter1 = stream.iterator().map(unzipper1);
1212+
final Iterator<T2> iter2 = stream.iterator().map(unzipper2);
1213+
return Tuple.of(iter1, iter2);
12111214
}
12121215
}
12131216

12141217
@Override
12151218
default <T1, T2, T3> Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> unzip3(
1216-
Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
1217-
Objects.requireNonNull(unzipper, "unzipper is null");
1219+
Function<? super T, ? extends T1> unzipper1,
1220+
Function<? super T, ? extends T2> unzipper2,
1221+
Function<? super T, ? extends T3> unzipper3) {
1222+
Objects.requireNonNull(unzipper1, "unzipper1 is null");
1223+
Objects.requireNonNull(unzipper2, "unzipper2 is null");
1224+
Objects.requireNonNull(unzipper3, "unzipper3 is null");
12181225
if (!hasNext()) {
12191226
return Tuple.of(empty(), empty(), empty());
12201227
} else {
1221-
final Stream<Tuple3<? extends T1, ? extends T2, ? extends T3>> source = Stream.ofAll(map(unzipper));
1222-
return Tuple.of(source.map(t -> (T1) t._1).iterator(), source.map(t -> (T2) t._2).iterator(), source.map(t -> (T3) t._3).iterator());
1228+
final Stream<T> stream = Stream.ofAll(() -> this);
1229+
final Iterator<T1> iter1 = stream.iterator().map(unzipper1);
1230+
final Iterator<T2> iter2 = stream.iterator().map(unzipper2);
1231+
final Iterator<T3> iter3 = stream.iterator().map(unzipper3);
1232+
return Tuple.of(iter1, iter2, iter3);
12231233
}
12241234
}
12251235

src/main/java/io/vavr/collection/LinearSeq.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,6 @@ default int segmentLength(Predicate<? super T> predicate, int from) {
348348
@Override
349349
LinearSeq<T> takeRightWhile(Predicate<? super T> predicate);
350350

351-
@Override
352-
<T1, T2> Tuple2<? extends LinearSeq<T1>, ? extends LinearSeq<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper);
353-
354351
@Override
355352
LinearSeq<T> update(int index, T element);
356353

src/main/java/io/vavr/collection/LinkedHashSet.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -918,22 +918,6 @@ public LinkedHashSet<T> union(Set<? extends T> elements) {
918918
}
919919
}
920920

921-
@Override
922-
public <T1, T2> Tuple2<LinkedHashSet<T1>, LinkedHashSet<T2>> unzip(
923-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
924-
Objects.requireNonNull(unzipper, "unzipper is null");
925-
final Tuple2<Iterator<T1>, Iterator<T2>> t = iterator().unzip(unzipper);
926-
return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2));
927-
}
928-
929-
@Override
930-
public <T1, T2, T3> Tuple3<LinkedHashSet<T1>, LinkedHashSet<T2>, LinkedHashSet<T3>> unzip3(
931-
Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
932-
Objects.requireNonNull(unzipper, "unzipper is null");
933-
final Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> t = iterator().unzip3(unzipper);
934-
return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2), LinkedHashSet.ofAll(t._3));
935-
}
936-
937921
@Override
938922
public <U> LinkedHashSet<Tuple2<T, U>> zip(Iterable<? extends U> that) {
939923
return zipWith(that, Tuple::of);

src/main/java/io/vavr/collection/List.java

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,36 +1620,6 @@ public final <U> U transform(Function<? super List<T>, ? extends U> f) {
16201620
return f.apply(this);
16211621
}
16221622

1623-
@Override
1624-
public final <T1, T2> Tuple2<List<T1>, List<T2>> unzip(
1625-
Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
1626-
Objects.requireNonNull(unzipper, "unzipper is null");
1627-
List<T1> xs = Nil.instance();
1628-
List<T2> ys = Nil.instance();
1629-
for (T element : this) {
1630-
final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(element);
1631-
xs = xs.prepend(t._1);
1632-
ys = ys.prepend(t._2);
1633-
}
1634-
return Tuple.of(xs.reverse(), ys.reverse());
1635-
}
1636-
1637-
@Override
1638-
public final <T1, T2, T3> Tuple3<List<T1>, List<T2>, List<T3>> unzip3(
1639-
Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
1640-
Objects.requireNonNull(unzipper, "unzipper is null");
1641-
List<T1> xs = Nil.instance();
1642-
List<T2> ys = Nil.instance();
1643-
List<T3> zs = Nil.instance();
1644-
for (T element : this) {
1645-
final Tuple3<? extends T1, ? extends T2, ? extends T3> t = unzipper.apply(element);
1646-
xs = xs.prepend(t._1);
1647-
ys = ys.prepend(t._2);
1648-
zs = zs.prepend(t._3);
1649-
}
1650-
return Tuple.of(xs.reverse(), ys.reverse(), zs.reverse());
1651-
}
1652-
16531623
@Override
16541624
public final List<T> update(int index, T element) {
16551625
if (isEmpty()) {

src/main/java/io/vavr/collection/Map.java

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@
8484
* <li>{@link #mapKeys(Function, BiFunction)}</li>
8585
* <li>{@link #mapValues(Function)}</li>
8686
* <li>{@link #transform(Function)}</li>
87-
* <li>{@link #unzip(BiFunction)}</li>
88-
* <li>{@link #unzip3(BiFunction)}</li>
87+
* <li>{@link #unzip(Function, Function)}</li>
88+
* <li>{@link #unzip3(Function, Function, Function)}</li>
8989
* </ul>
9090
*
9191
* @param <K> Key type
@@ -593,31 +593,8 @@ default <U> U transform(Function<? super Map<K, V>, ? extends U> f) {
593593
return f.apply(this);
594594
}
595595

596-
default Tuple2<Seq<K>, Seq<V>> unzip() {
597-
return unzip(Function.identity());
598-
}
599-
600-
default <T1, T2> Tuple2<Seq<T1>, Seq<T2>> unzip(BiFunction<? super K, ? super V, Tuple2<? extends T1, ? extends T2>> unzipper) {
601-
Objects.requireNonNull(unzipper, "unzipper is null");
602-
return unzip(entry -> unzipper.apply(entry._1, entry._2));
603-
}
604-
605-
@Override
606-
default <T1, T2> Tuple2<Seq<T1>, Seq<T2>> unzip(Function<? super Tuple2<K, V>, Tuple2<? extends T1, ? extends T2>> unzipper) {
607-
Objects.requireNonNull(unzipper, "unzipper is null");
608-
return iterator().unzip(unzipper).map(Stream::ofAll, Stream::ofAll);
609-
}
610-
611-
default <T1, T2, T3> Tuple3<Seq<T1>, Seq<T2>, Seq<T3>> unzip3(BiFunction<? super K, ? super V, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
612-
Objects.requireNonNull(unzipper, "unzipper is null");
613-
return unzip3(entry -> unzipper.apply(entry._1, entry._2));
614-
}
615-
616-
@Override
617-
default <T1, T2, T3> Tuple3<Seq<T1>, Seq<T2>, Seq<T3>> unzip3(
618-
Function<? super Tuple2<K, V>, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
619-
Objects.requireNonNull(unzipper, "unzipper is null");
620-
return iterator().unzip3(unzipper).map(Stream::ofAll, Stream::ofAll, Stream::ofAll);
596+
default Tuple2<Iterator<K>, Iterator<V>> unzip() {
597+
return unzip(entry -> entry._1, entry -> entry._2);
621598
}
622599

623600
/**

0 commit comments

Comments
 (0)