Skip to content

Instantly share code, notes, and snippets.

@forax
Created August 12, 2014 12:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forax/6211ceace9f31c8989bf to your computer and use it in GitHub Desktop.
Save forax/6211ceace9f31c8989bf to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public interface Tuples {
abstract class Tuple {
abstract int size();
abstract Object get(int index);
@Override
public final boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
Tuple tuple = (Tuple)obj;
return IntStream.range(0, size()).allMatch(i -> get(i).equals(tuple.get(i)));
}
@Override
public final int hashCode() {
int hash = 1;
int size = size();
for(int i = 0; i < size; i++) {
hash = hash * 31 + get(i).hashCode();
}
return hash;
}
@Override
public final String toString() {
return IntStream.range(0, size()).mapToObj(i -> get(i).toString()).collect(Collectors.joining(", ", "Tuple[", "]"));
}
static <T extends Tuple> List<T> zip(Function<? super Object[], T> factory, List<?>... lists) {
ArrayList<T> result = new ArrayList<>();
Iterator<?>[] its = Arrays.stream(lists).map(List::iterator).toArray(Iterator[]::new);
for(;;) {
boolean hasNext = its[0].hasNext();
Stream<Iterator<?>> stream = Arrays.stream(its).skip(1);
if (!(hasNext? stream.allMatch(Iterator::hasNext): stream.noneMatch(Iterator::hasNext))) {
throw new IllegalStateException("not the same size");
}
if (!hasNext) {
return result;
}
result.add(factory.apply(Arrays.stream(its).map(Iterator::next).toArray()));
}
}
}
public static final class Tuple2<A,B> extends Tuple {
public final A elem0;
public final B elem1;
public Tuple2(A elem0, B elem1) {
this.elem0 = Objects.requireNonNull(elem0);
this.elem1 = Objects.requireNonNull(elem1);
}
@Override
int size() {
return 2;
}
@Override
Object get(int index) {
switch(index) {
case 0:
return elem0;
case 1:
return elem1;
default:
throw new IndexOutOfBoundsException();
}
}
@SuppressWarnings("unchecked")
public static <A, B> List<Tuple2<A, B>> zip(List<? extends A> lista, List<? extends B> listb) {
return zip(args -> new Tuple2<>((A)args[0], (B)args[1]), lista, listb);
}
}
public static final class Tuple3<A,B,C> extends Tuple {
public final A elem0;
public final B elem1;
public final C elem2;
public Tuple3(A elem0, B elem1, C elem2) {
this.elem0 = Objects.requireNonNull(elem0);
this.elem1 = Objects.requireNonNull(elem1);
this.elem2 = Objects.requireNonNull(elem2);
}
@Override
int size() {
return 3;
}
@Override
Object get(int index) {
switch(index) {
case 0:
return elem0;
case 1:
return elem1;
case 2:
return elem2;
default:
throw new IndexOutOfBoundsException();
}
}
@SuppressWarnings("unchecked")
public static <A, B, C> List<Tuple3<A, B, C>> zip(List<? extends A> lista, List<? extends B> listb, List<? extends C> listc) {
return zip(args -> new Tuple3<>((A)args[0], (B)args[1], (C)args[2]), lista, listb, listc);
}
}
public static void main(String[] args) {
Tuple2<String, String> pair1 = new Tuple2<>("foo", "bar");
Tuple2<String, String> pair2 = new Tuple2<>("foo", "bar");
System.out.println(pair1.hashCode() + " " + pair2.hashCode());
System.out.println(pair1.equals(pair2));
List<Tuple2<String, Integer>> zip2 = Tuple2.zip(Arrays.asList("foo", "bar"), Arrays.asList(1, 2));
System.out.println(zip2);
List<Tuple3<String, Integer, Boolean>> zip3 = Tuple3.zip(Arrays.asList("foo", "bar"), Arrays.asList(1, 2), Arrays.asList(true, false));
System.out.println(zip3);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment