Skip to content

Commit

Permalink
Merge pull request #508 from ruslansennov/zipunzip
Browse files Browse the repository at this point in the history
zip*/unzip methods added #487
  • Loading branch information
danieldietrich committed Aug 24, 2015
2 parents 5285156 + 88bbc12 commit d1ce115
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 11 deletions.
18 changes: 9 additions & 9 deletions src/main/java/javaslang/collection/HashSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public HashSet<T> drop(int n) {
if (n <= 0) {
return this;
} else {
return HashSet.ofAll(() -> iterator().drop(n));
return HashSet.ofAll(iterator().drop(n));
}
}

Expand All @@ -181,15 +181,15 @@ public HashSet<T> dropRight(int n) {
@Override
public HashSet<T> dropWhile(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final List<T> dropped = list.get().dropWhile(predicate);
return dropped.length() == list.get().length() ? this : HashSet.ofAll(dropped);
final HashSet<T> dropped = HashSet.ofAll(iterator().dropWhile(predicate));
return dropped.length() == length() ? this : dropped;
}

@Override
public HashSet<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final List<T> filtered = list.get().filter(predicate);
return filtered.length() == list.get().length() ? this : HashSet.ofAll(filtered);
final HashSet<T> filtered = HashSet.ofAll(iterator().filter(predicate));
return filtered.length() == length() ? this : filtered;
}

@Override
Expand Down Expand Up @@ -453,25 +453,25 @@ public HashSet<T> takeWhile(Predicate<? super T> predicate) {
@Override
public <T1, T2> Tuple2<HashSet<T1>, HashSet<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
Tuple2<List<T1>, List<T2>> t = list.get().unzip(unzipper);
Tuple2<Iterator<T1>, Iterator<T2>> t = iterator().unzip(unzipper);
return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2));
}

@Override
public <U> HashSet<Tuple2<T, U>> zip(Iterable<U> that) {
Objects.requireNonNull(that, "that is null");
return HashSet.ofAll(list.get().zip(that));
return HashSet.ofAll(iterator().zip(that));
}

@Override
public <U> HashSet<Tuple2<T, U>> zipAll(Iterable<U> that, T thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
return HashSet.ofAll(list.get().zipAll(that, thisElem, thatElem));
return HashSet.ofAll(iterator().zipAll(that, thisElem, thatElem));
}

@Override
public HashSet<Tuple2<T, Integer>> zipWithIndex() {
return HashSet.ofAll(list.get().zipWithIndex());
return HashSet.ofAll(iterator().zipWithIndex());
}

@Override
Expand Down
119 changes: 117 additions & 2 deletions src/main/java/javaslang/collection/Iterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package javaslang.collection;

import javaslang.Tuple;
import javaslang.Tuple2;
import javaslang.Value;
import javaslang.control.None;
Expand Down Expand Up @@ -323,7 +324,37 @@ default Iterator<T> dropRight(int n) {

@Override
default Iterator<T> dropWhile(Predicate<? super T> predicate) {
return null;
Objects.requireNonNull(predicate, "predicate is null");
if (!hasNext()) {
return empty();
} else {
final Iterator<T> that = this;
return new Iterator<T>() {

private T next = null;

@Override
public boolean hasNext() {
while (next == null && that.hasNext()) {
final T value = that.next();
if(!predicate.test(value)) {
next = value;
}
}
return next != null;
}

@Override
public T next() {
if (!hasNext()) {
EMPTY.next();
}
final T result = next;
next = null;
return result;
}
};
}
}

default boolean equals(Iterator<? extends T> that) {
Expand Down Expand Up @@ -378,11 +409,13 @@ public T next() {

@Override
default Iterator<T> findAll(Predicate<? super T> predicate) {
return null;
Objects.requireNonNull(predicate, "predicate is null");
return filter(predicate);
}

@Override
default Option<T> findLast(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return null;
}

Expand Down Expand Up @@ -569,6 +602,7 @@ public U next() {

@Override
default Tuple2<Iterator<T>, Iterator<T>> partition(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return null;
}

Expand Down Expand Up @@ -635,6 +669,7 @@ default Iterator<Iterator<T>> sliding(int size, int step) {

@Override
default Tuple2<Iterator<T>, Iterator<T>> span(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return null;
}

Expand Down Expand Up @@ -691,9 +726,89 @@ default Iterator<T> takeRight(int n) {

@Override
default Iterator<T> takeWhile(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return null;
}

default <U> Iterator<Tuple2<T, U>> zip(Iterable<U> that) {
Objects.requireNonNull(that, "that is null");
if(isEmpty()) {
return empty();
} else {
final Iterator<T> it1 = this;
final java.util.Iterator<U> it2 = that.iterator();
return new Iterator<Tuple2<T, U>>() {
@Override
public boolean hasNext() {
return it1.hasNext() && it2.hasNext();
}

@Override
public Tuple2<T, U> next() {
if (!hasNext()) {
EMPTY.next();
}
return Tuple.of(it1.next(), it2.next());
}
};
}
}

default <U> Iterator<Tuple2<T, U>> zipAll(Iterable<U> that, T thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
if(isEmpty()) {
return empty();
} else {
final Iterator<T> it1 = this;
final java.util.Iterator<U> it2 = that.iterator();
return new Iterator<Tuple2<T, U>>() {
@Override
public boolean hasNext() {
return it1.hasNext() || it2.hasNext();
}

@Override
public Tuple2<T, U> next() {
if (!hasNext()) {
EMPTY.next();
}
T v1 = it1.hasNext() ? it1.next() : thisElem;
U v2 = it2.hasNext() ? it2.next() : thatElem;
return Tuple.of(v1, v2);
}
};
}
}

default Iterator<Tuple2<T, Integer>> zipWithIndex() {
if(isEmpty()) {
return empty();
} else {
final Iterator<T> it1 = this;
return new Iterator<Tuple2<T, Integer>>() {
private int index = 0;
@Override
public boolean hasNext() {
return it1.hasNext();
}

@Override
public Tuple2<T, Integer> next() {
if (!hasNext()) {
EMPTY.next();
}
return Tuple.of(it1.next(), index++);
}
};
}
}

default <T1, T2> Tuple2<Iterator<T1>, Iterator<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
final Stream<Tuple2<? extends T1, ? extends T2>> source = Stream.ofAll(this.map(unzipper::apply));
return Tuple.of(source.map(t -> (T1) t._1).iterator(), source.map(t -> (T2) t._2).iterator());
}

class ConcatIterator<T> implements Iterator<T> {

private final Iterator<? extends Iterator<? extends T>> iterators;
Expand Down
118 changes: 118 additions & 0 deletions src/test/java/javaslang/collection/HashSetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*/
package javaslang.collection;

import javaslang.Tuple;
import javaslang.Tuple2;
import org.assertj.core.api.*;
import org.junit.Test;

Expand Down Expand Up @@ -147,6 +149,122 @@ int getPeekNonNilPerformingAnAction() {
return 1;
}

// TODO move to traversable
// -- zip

@Test
public void shouldZipNils() {
final HashSet<Tuple2<Object, Object>> actual = empty().zip(empty());
assertThat(actual).isEqualTo(empty());
}

@Test
public void shouldZipEmptyAndNonNil() {
final HashSet<Tuple2<Object, Integer>> actual = empty().zip(of(1));
assertThat(actual).isEqualTo(empty());
}

@Test
public void shouldZipNonEmptyAndNil() {
final HashSet<Tuple2<Integer, Integer>> actual = of(1).zip(empty());
assertThat(actual).isEqualTo(empty());
}

@Test
public void shouldZipNonNilsIfThisIsSmaller() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2).zip(of("a", "b", "c"));
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"));
assertThat(actual).isEqualTo(expected);
}

@Test
public void shouldZipNonNilsIfThatIsSmaller() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2, 3).zip(of("a", "b"));
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"));
assertThat(actual).isEqualTo(expected);
}

@Test
public void shouldZipNonNilsOfSameSize() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2, 3).zip(of("a", "b", "c"));
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"), Tuple.of(3, "c"));
assertThat(actual).isEqualTo(expected);
}

@Test(expected = NullPointerException.class)
public void shouldThrowIfZipWithThatIsNull() {
empty().zip(null);
}

// TODO move to traversable
// -- zipAll

@Test
public void shouldZipAllNils() {
// ignore
}

@Test
public void shouldZipAllEmptyAndNonNil() {
// ignore
}

@Test
public void shouldZipAllNonEmptyAndNil() {
final HashSet<?> actual = of(1).zipAll(empty(), null, null);
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, Object>> expected = of(Tuple.of(1, null));
assertThat(actual).isEqualTo(expected);
}

@Test
public void shouldZipAllNonNilsIfThisIsSmaller() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2).zipAll(of("a", "b", "c"), 9, "z");
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"), Tuple.of(9, "c"));
assertThat(actual).isEqualTo(expected);
}

@Test
public void shouldZipAllNonNilsIfThatIsSmaller() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2, 3).zipAll(of("a", "b"), 9, "z");
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"), Tuple.of(3, "z"));
assertThat(actual).isEqualTo(expected);
}

@Test
public void shouldZipAllNonNilsOfSameSize() {
final HashSet<Tuple2<Integer, String>> actual = of(1, 2, 3).zipAll(of("a", "b", "c"), 9, "z");
@SuppressWarnings("unchecked")
final HashSet<Tuple2<Integer, String>> expected = of(Tuple.of(1, "a"), Tuple.of(2, "b"), Tuple.of(3, "c"));
assertThat(actual).isEqualTo(expected);
}

@Test(expected = NullPointerException.class)
public void shouldThrowIfZipAllWithThatIsNull() {
empty().zipAll(null, null, null);
}

// TODO move to traversable
// -- zipWithIndex

@Test
public void shouldZipNilWithIndex() {
assertThat(this.<String> empty().zipWithIndex()).isEqualTo(this.<Tuple2<String, Integer>> empty());
}

@Test
public void shouldZipNonNilWithIndex() {
final HashSet<Tuple2<String, Integer>> actual = of("a", "b", "c").zipWithIndex();
@SuppressWarnings("unchecked")
final HashSet<Tuple2<String, Integer>> expected = of(Tuple.of("a", 0), Tuple.of("b", 1), Tuple.of("c", 2));
assertThat(actual).isEqualTo(expected);
}

// HashSet special cases

@Override
Expand Down

0 comments on commit d1ce115

Please sign in to comment.