我创建了一些tuple
类,并将它们放入Java集合中。但是我不想在迭代集合时直接使用tuple
作为函数参数。所以我实现了元组解包,如下面的代码。
基本上它可以工作,但问题是需要进行类型转换:
map((Func2<Long, Long, Long>) (a, b) -> a + b)
有没有办法在这里删除类型转换?
修改
也许我没有说清楚,不仅tuple2
,而且tuple3
,tuple4
......应该得到支持。 @Flown的回答对Tuple2
有很大帮助,但在此期间对tuple2
,tuple3
,tuple4
不起作用
package test;
import com.google.common.collect.Iterables;
import java.util.Arrays;
import java.util.function.Function;
import static test.TupleIterable.Tuple.tuple;
public interface TupleIterable<T> {
Iterable<T> apply();
static <E> TupleIterable<E> from(Iterable<E> iterable) {
return () -> iterable;
}
default <E> TupleIterable<E> map(Function<? super T, ? extends E> op) {
return () -> Iterables.transform(TupleIterable.this.apply(), op::apply);
}
interface Func2<T1, T2, R> extends Function<Tuple.Tuple2<T1, T2>, R> {
R apply(T1 t1, T2 t2);
@Override
default R apply(Tuple.Tuple2<T1, T2> t) {
return apply(t.t1, t.t2);
}
}
interface Func3<T1, T2, T3, R> extends Function<Tuple.Tuple3<T1, T2, T3>, R> {
R apply(T1 t1, T2 t2, T3 t3);
@Override
default R apply(Tuple.Tuple3<T1, T2, T3> t) {
return apply(t.t1, t.t2, t.t3);
}
}
interface Tuple {
static <T1, T2> Tuple2<T1, T2> tuple(T1 t1, T2 t2) {
return new Tuple2<>(t1, t2);
}
static <T1, T2, T3> Tuple3<T1, T2, T3> tuple(T1 t1, T2 t2, T3 t3) {
return new Tuple3<>(t1, t2, t3);
}
class Tuple2<T1, T2> implements Tuple {
public T1 t1;
public T2 t2;
public Tuple2(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}
}
class Tuple3<T1, T2, T3> implements Tuple {
public T1 t1;
public T2 t2;
public T3 t3;
public Tuple3(T1 t1, T2 t2, T3 t3) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
}
}
public static void main(String[] args) {
TupleIterable.from(Arrays.asList(1L, 2L))
.map(x -> tuple(x, x)) // map long to tuple2
.map((Func2<Long, Long, Tuple.Tuple3<Long, Long, Long>>) (a, b) -> tuple(a, b, a + b)) // map tuple2 to tuple3
.map((Func3<Long, Long, Long, Long>) (a, b, c) -> a + b + c) // map tuple3 to Long
.apply()
.forEach(System.out::println);
}
}
答案 0 :(得分:3)
您可以执行与JDK开发人员针对基本类型的Stream
特化所做的相同的技巧。在不同的界面中引入mapToTuple
和unwrap
。
我重写了一些代码并使用了一些现有的FunctionalInterfaces
。
import java.util.Arrays;
import java.util.Iterator;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
public class Test {
public static void main(String... args) {
MyIterable.from(Arrays.asList(1L, 2L)).mapToTuple(l -> Tuple2.tuple(l, l + 1L)).unwrap((a, b) -> a + b).get()
.forEach(System.out::println);
}
}
final class Tuple2<T1, T2> {
public static <T1, T2> Tuple2<T1, T2> tuple(T1 t1, T2 t2) {
return new Tuple2<>(t1, t2);
}
public final T1 t1;
public final T2 t2;
private Tuple2(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}
}
@FunctionalInterface
interface TupleIterable<T1, T2> extends Supplier<Iterable<Tuple2<T1, T2>>> {
default <E> MyIterable<E> unwrap(BiFunction<T1, T2, E> func) {
return () -> Iterables.transform(get(), t -> func.apply(t.t1, t.t2));
}
}
@FunctionalInterface
interface MyIterable<T> extends Supplier<Iterable<T>> {
static <E> MyIterable<E> from(Iterable<E> iterable) {
return () -> iterable;
}
default <E> MyIterable<E> map(Function<? super T, ? extends E> mapper) {
return () -> Iterables.transform(get(), mapper::apply);
}
default <T1, T2> TupleIterable<T1, T2> mapToTuple(Function<? super T, ? extends Tuple2<T1, T2>> tupleMapper) {
return () -> Iterables.transform(get(), tupleMapper::apply);
}
}
final class Iterables {
public static <T, E> Iterable<E> transform(Iterable<T> iterable, Function<? super T, ? extends E> mapper) {
return () -> new Iterator<E>() {
private final Iterator<T> iter = iterable.iterator();
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public E next() {
return mapper.apply(iter.next());
}
};
}
}
答案 1 :(得分:1)
我没有进行类型转换,而是创建了一个unpack
函数来解包元组。它的工作方式与map(unpack((a, b) -> tuple(a, b, a + b)))
类似,但仍然不够直观。
package test;
import com.google.common.collect.Iterables;
import java.util.Arrays;
import java.util.function.Function;
import static test.TupleIterable.Func.unpack;
import static test.TupleIterable.Tuple.tuple;
public interface TupleIterable<T> {
Iterable<T> apply();
static <E> TupleIterable<E> from(Iterable<E> iterable) {
return () -> iterable;
}
default <E> TupleIterable<E> map(Function<? super T, E> op) {
return () -> Iterables.transform(TupleIterable.this.apply(), op::apply);
}
interface Func {
static <T1, T2, R> Function<Tuple.Tuple2<T1, T2>, R> unpack(Func2<T1, T2, R> f) {
return t -> f.apply(t.t1, t.t2);
}
static <T1, T2, T3, R> Function<Tuple.Tuple3<T1, T2, T3>, R> unpack(Func3<T1, T2, T3, R> f) {
return t -> f.apply(t.t1, t.t2, t.t3);
}
@FunctionalInterface
interface Func2<T1, T2, R> {
R apply(T1 t1, T2 t2);
}
@FunctionalInterface
interface Func3<T1, T2, T3, R> {
R apply(T1 t1, T2 t2, T3 t3);
}
}
interface Tuple {
static <T1, T2> Tuple2<T1, T2> tuple(T1 t1, T2 t2) {
return new Tuple2<>(t1, t2);
}
static <T1, T2, T3> Tuple3<T1, T2, T3> tuple(T1 t1, T2 t2, T3 t3) {
return new Tuple3<>(t1, t2, t3);
}
class Tuple2<T1, T2> implements Tuple {
public T1 t1;
public T2 t2;
public Tuple2(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}
}
class Tuple3<T1, T2, T3> implements Tuple {
public T1 t1;
public T2 t2;
public T3 t3;
public Tuple3(T1 t1, T2 t2, T3 t3) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
}
}
public static void main(String[] args) {
TupleIterable.from(Arrays.asList(1L, 2L))
.map(x -> tuple(x, x)) // map long to tuple2
.map(unpack((a, b) -> tuple(a, b, a + b))) // map tuple2 to tuple3
.map(unpack((a, b, c) -> a + b + c)) // map tuple3 to Long
.apply()
.forEach(System.out::println);
}
}
答案 2 :(得分:0)
我无法确定这是否太“脏”,但为什么不在T1
内为T2
和Tuple2
提供getter并执行:
.map(x -> tuple(x, x + 1)) // map long to tuple2
.map(a -> a.getT1() + a.getT2()) // map tuple2 to long