Skip to content

Commit b73e537

Browse files
committed
Add zip api to cast three sequence into a Tuple3 sequence
1 parent 0cf0f41 commit b73e537

File tree

4 files changed

+202
-18
lines changed

4 files changed

+202
-18
lines changed

src/main/java/com/bestvike/linq/IEnumerable.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import com.bestvike.linq.util.ArrayUtils;
7272
import com.bestvike.linq.util.Formatter;
7373
import com.bestvike.tuple.Tuple2;
74+
import com.bestvike.tuple.Tuple3;
7475

7576
import java.math.BigDecimal;
7677
import java.util.Comparator;
@@ -1085,11 +1086,15 @@ default IEnumerable<TSource> where(IndexPredicate2<? super TSource> predicate) {
10851086
return Where.where(this, (IndexPredicate2<TSource>) predicate);
10861087
}
10871088

1089+
default <TSecond, TResult> IEnumerable<TResult> zip(IEnumerable<? extends TSecond> second, Func2<? super TSource, ? super TSecond, ? extends TResult> resultSelector) {
1090+
return Zip.zip(this, (IEnumerable<TSecond>) second, (Func2<TSource, TSecond, TResult>) resultSelector);
1091+
}
1092+
10881093
default <TSecond> IEnumerable<Tuple2<TSource, TSecond>> zip(IEnumerable<? extends TSecond> second) {
10891094
return Zip.zip(this, (IEnumerable<TSecond>) second);
10901095
}
10911096

1092-
default <TSecond, TResult> IEnumerable<TResult> zip(IEnumerable<? extends TSecond> second, Func2<? super TSource, ? super TSecond, ? extends TResult> resultSelector) {
1093-
return Zip.zip(this, (IEnumerable<TSecond>) second, (Func2<TSource, TSecond, TResult>) resultSelector);
1097+
default <TSecond, TThird> IEnumerable<Tuple3<TSource, TSecond, TThird>> zip(IEnumerable<? extends TSecond> second, IEnumerable<? extends TThird> third) {
1098+
return Zip.zip(this, (IEnumerable<TSecond>) second, (IEnumerable<TThird>) third);
10941099
}
10951100
}

src/main/java/com/bestvike/linq/enumerable/Zip.java

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.bestvike.linq.exception.ExceptionArgument;
77
import com.bestvike.linq.exception.ThrowHelper;
88
import com.bestvike.tuple.Tuple2;
9+
import com.bestvike.tuple.Tuple3;
910

1011
/**
1112
* Created by 许崇雷 on 2018-05-09.
@@ -14,42 +15,105 @@ public final class Zip {
1415
private Zip() {
1516
}
1617

18+
public static <TFirst, TSecond, TResult> IEnumerable<TResult> zip(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func2<TFirst, TSecond, TResult> resultSelector) {
19+
if (first == null)
20+
ThrowHelper.throwArgumentNullException(ExceptionArgument.first);
21+
if (second == null)
22+
ThrowHelper.throwArgumentNullException(ExceptionArgument.second);
23+
if (resultSelector == null)
24+
ThrowHelper.throwArgumentNullException(ExceptionArgument.resultSelector);
25+
26+
return new ZipIterator<>(first, second, resultSelector);
27+
}
28+
1729
public static <TFirst, TSecond> IEnumerable<Tuple2<TFirst, TSecond>> zip(IEnumerable<TFirst> first, IEnumerable<TSecond> second) {
1830
if (first == null)
1931
ThrowHelper.throwArgumentNullException(ExceptionArgument.first);
2032
if (second == null)
2133
ThrowHelper.throwArgumentNullException(ExceptionArgument.second);
2234

23-
return new ZipIterator<>(first, second);
35+
return new ZipIterator2<>(first, second);
2436
}
2537

26-
public static <TFirst, TSecond, TResult> IEnumerable<TResult> zip(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func2<TFirst, TSecond, TResult> resultSelector) {
38+
public static <TFirst, TSecond, TThird> IEnumerable<Tuple3<TFirst, TSecond, TThird>> zip(IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third) {
2739
if (first == null)
2840
ThrowHelper.throwArgumentNullException(ExceptionArgument.first);
2941
if (second == null)
3042
ThrowHelper.throwArgumentNullException(ExceptionArgument.second);
31-
if (resultSelector == null)
32-
ThrowHelper.throwArgumentNullException(ExceptionArgument.resultSelector);
43+
if (third == null)
44+
ThrowHelper.throwArgumentNullException(ExceptionArgument.third);
45+
46+
return new ZipIterator3<>(first, second, third);
47+
}
48+
}
49+
50+
51+
final class ZipIterator<TFirst, TSecond, TResult> extends AbstractIterator<TResult> {
52+
private final IEnumerable<TFirst> first;
53+
private final IEnumerable<TSecond> second;
54+
private final Func2<TFirst, TSecond, TResult> resultSelector;
55+
private IEnumerator<TFirst> firstEnumerator;
56+
private IEnumerator<TSecond> secondEnumerator;
57+
58+
ZipIterator(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func2<TFirst, TSecond, TResult> resultSelector) {
59+
this.first = first;
60+
this.second = second;
61+
this.resultSelector = resultSelector;
62+
}
63+
64+
@Override
65+
public AbstractIterator<TResult> clone() {
66+
return new ZipIterator<>(this.first, this.second, this.resultSelector);
67+
}
68+
69+
@Override
70+
public boolean moveNext() {
71+
switch (this.state) {
72+
case 1:
73+
this.firstEnumerator = this.first.enumerator();
74+
this.secondEnumerator = this.second.enumerator();
75+
this.state = 2;
76+
case 2:
77+
if (this.firstEnumerator.moveNext() && this.secondEnumerator.moveNext()) {
78+
this.current = this.resultSelector.apply(this.firstEnumerator.current(), this.secondEnumerator.current());
79+
return true;
80+
}
81+
this.close();
82+
return false;
83+
default:
84+
return false;
85+
}
86+
}
3387

34-
return new ZipIterator2<>(first, second, resultSelector);
88+
@Override
89+
public void close() {
90+
if (this.firstEnumerator != null) {
91+
this.firstEnumerator.close();
92+
this.firstEnumerator = null;
93+
}
94+
if (this.secondEnumerator != null) {
95+
this.secondEnumerator.close();
96+
this.secondEnumerator = null;
97+
}
98+
super.close();
3599
}
36100
}
37101

38102

39-
final class ZipIterator<TFirst, TSecond> extends AbstractIterator<Tuple2<TFirst, TSecond>> {
103+
final class ZipIterator2<TFirst, TSecond> extends AbstractIterator<Tuple2<TFirst, TSecond>> {
40104
private final IEnumerable<TFirst> first;
41105
private final IEnumerable<TSecond> second;
42106
private IEnumerator<TFirst> firstEnumerator;
43107
private IEnumerator<TSecond> secondEnumerator;
44108

45-
ZipIterator(IEnumerable<TFirst> first, IEnumerable<TSecond> second) {
109+
ZipIterator2(IEnumerable<TFirst> first, IEnumerable<TSecond> second) {
46110
this.first = first;
47111
this.second = second;
48112
}
49113

50114
@Override
51115
public AbstractIterator<Tuple2<TFirst, TSecond>> clone() {
52-
return new ZipIterator<>(this.first, this.second);
116+
return new ZipIterator2<>(this.first, this.second);
53117
}
54118

55119
@Override
@@ -86,22 +150,23 @@ public void close() {
86150
}
87151

88152

89-
final class ZipIterator2<TFirst, TSecond, TResult> extends AbstractIterator<TResult> {
153+
final class ZipIterator3<TFirst, TSecond, TThird> extends AbstractIterator<Tuple3<TFirst, TSecond, TThird>> {
90154
private final IEnumerable<TFirst> first;
91155
private final IEnumerable<TSecond> second;
92-
private final Func2<TFirst, TSecond, TResult> resultSelector;
156+
private final IEnumerable<TThird> third;
93157
private IEnumerator<TFirst> firstEnumerator;
94158
private IEnumerator<TSecond> secondEnumerator;
159+
private IEnumerator<TThird> thirdEnumerator;
95160

96-
ZipIterator2(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func2<TFirst, TSecond, TResult> resultSelector) {
161+
ZipIterator3(IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third) {
97162
this.first = first;
98163
this.second = second;
99-
this.resultSelector = resultSelector;
164+
this.third = third;
100165
}
101166

102167
@Override
103-
public AbstractIterator<TResult> clone() {
104-
return new ZipIterator2<>(this.first, this.second, this.resultSelector);
168+
public AbstractIterator<Tuple3<TFirst, TSecond, TThird>> clone() {
169+
return new ZipIterator3<>(this.first, this.second, this.third);
105170
}
106171

107172
@Override
@@ -110,10 +175,11 @@ public boolean moveNext() {
110175
case 1:
111176
this.firstEnumerator = this.first.enumerator();
112177
this.secondEnumerator = this.second.enumerator();
178+
this.thirdEnumerator = this.third.enumerator();
113179
this.state = 2;
114180
case 2:
115-
if (this.firstEnumerator.moveNext() && this.secondEnumerator.moveNext()) {
116-
this.current = this.resultSelector.apply(this.firstEnumerator.current(), this.secondEnumerator.current());
181+
if (this.firstEnumerator.moveNext() && this.secondEnumerator.moveNext() && this.thirdEnumerator.moveNext()) {
182+
this.current = new Tuple3<>(this.firstEnumerator.current(), this.secondEnumerator.current(), this.thirdEnumerator.current());
117183
return true;
118184
}
119185
this.close();
@@ -133,6 +199,10 @@ public void close() {
133199
this.secondEnumerator.close();
134200
this.secondEnumerator = null;
135201
}
202+
if (this.thirdEnumerator != null) {
203+
this.thirdEnumerator.close();
204+
this.thirdEnumerator = null;
205+
}
136206
super.close();
137207
}
138208
}

src/main/java/com/bestvike/linq/exception/ExceptionArgument.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public enum ExceptionArgument {
2121
second,
2222
selector,
2323
source,
24+
third,
2425
//extension
2526
action,
2627
array,

src/test/java/com/bestvike/linq/enumerable/ZipTest.java

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.bestvike.linq.exception.ArgumentNullException;
99
import com.bestvike.tuple.Tuple;
1010
import com.bestvike.tuple.Tuple2;
11+
import com.bestvike.tuple.Tuple3;
1112
import org.junit.jupiter.api.Test;
1213

1314
import java.util.Arrays;
@@ -550,6 +551,113 @@ void Zip2_TupleNames() {
550551
assertEquals(2, t.getItem2());
551552
}
552553

554+
@Test
555+
void Zip3_FirstIsNull() {
556+
IEnumerable<Integer> first = null;
557+
IEnumerable<Integer> second = Linq.of(new int[]{4, 5, 6});
558+
IEnumerable<Integer> third = Linq.of(new int[]{7, 8, 9});
559+
560+
assertThrows(NullPointerException.class, () -> first.zip(second, third));
561+
}
562+
563+
@Test
564+
void Zip3_SecondIsNull() {
565+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2, 3});
566+
IEnumerable<Integer> second = null;
567+
IEnumerable<Integer> third = Linq.of(new int[]{4, 5, 6});
568+
569+
assertThrows(ArgumentNullException.class, () -> first.zip(second, third));
570+
}
571+
572+
@Test
573+
void Zip3_ThirdIsNull() {
574+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2, 3});
575+
IEnumerable<Integer> second = Linq.of(new int[]{4, 5, 6});
576+
IEnumerable<Integer> third = null;
577+
578+
assertThrows(ArgumentNullException.class, () -> first.zip(second, third));
579+
}
580+
581+
@Test
582+
void Zip3_ThirdEmpty() {
583+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2, 3});
584+
IEnumerable<Integer> second = Linq.of(new int[]{4, 5, 6});
585+
IEnumerable<Integer> third = Linq.of(new int[0]);
586+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.empty();
587+
588+
assertEquals(expected, first.zip(second, third));
589+
}
590+
591+
@Test
592+
void Zip3_ImplicitTypeParameters() {
593+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
594+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
595+
IEnumerable<Integer> third = Linq.of(new int[]{5, 6});
596+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5), Tuple.create(2, 4, 6));
597+
598+
assertEquals(expected, first.zip(second, third));
599+
}
600+
601+
@Test
602+
void Zip3_ExplicitTypeParameters() {
603+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
604+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
605+
IEnumerable<Integer> third = Linq.of(new int[]{5, 6});
606+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5), Tuple.create(2, 4, 6));
607+
608+
assertEquals(expected, first.zip(second, third));
609+
}
610+
611+
@Test
612+
void Zip3_ThirdOneMore() {
613+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
614+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
615+
IEnumerable<Integer> third = Linq.of(new int[]{5, 6, 7});
616+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5), Tuple.create(2, 4, 6));
617+
618+
assertEquals(expected, first.zip(second, third));
619+
}
620+
621+
@Test
622+
void Zip3_ThirdManyMore() {
623+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
624+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
625+
IEnumerable<Integer> third = Linq.of(new int[]{5, 6, 7, 8});
626+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5), Tuple.create(2, 4, 6));
627+
628+
assertEquals(expected, first.zip(second, third));
629+
}
630+
631+
@Test
632+
void Zip3_ThirdOneLess() {
633+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
634+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
635+
IEnumerable<Integer> third = Linq.of(new int[]{5});
636+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5));
637+
638+
assertEquals(expected, first.zip(second, third));
639+
}
640+
641+
@Test
642+
void Zip3_ThirdManyLess() {
643+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2, 3});
644+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4, 5});
645+
IEnumerable<Integer> third = Linq.of(new int[]{5});
646+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5));
647+
648+
assertEquals(expected, first.zip(second, third));
649+
}
650+
651+
@Test
652+
void Zip3_RunOnce() {
653+
IEnumerable<Integer> first = Linq.of(new int[]{1, 2});
654+
IEnumerable<Integer> second = Linq.of(new int[]{3, 4});
655+
IEnumerable<Integer> third = Linq.of(new int[]{5, 6});
656+
IEnumerable<Tuple3<Integer, Integer, Integer>> expected = Linq.of(Tuple.create(1, 3, 5), Tuple.create(2, 4, 6));
657+
658+
assertEquals(expected, first.runOnce().zip(second.runOnce(), third.runOnce()));
659+
}
660+
553661
@Test
554662
void testZip() {
555663
IEnumerable<String> e1 = Linq.of(Arrays.asList("a", "b", "c"));

0 commit comments

Comments
 (0)