LINQ Join的Java8流API等价物是什么?

LINQ Join的Java8流API等价物是什么?,java,c#,.net,linq,join,Java,C#,.net,Linq,Join,在C#/.Net中,可以使用扩展方法Enumerable连接IEnumerable序列。。。在路上 Java8(流API)中有类似的东西吗?或者什么是模拟可枚举.连接的最佳方法 见: 我还没有找到任何现有的等效方法,但下面的方法应该有效: public static <Outer, Inner, Key, Result> Stream<Result> join( Stream<Outer> outer, Stream<Inner>

在C#/.Net中,可以使用扩展方法Enumerable连接IEnumerable序列。。。在路上

Java8(流API)中有类似的东西吗?或者什么是模拟可枚举.连接的最佳方法

见:

我还没有找到任何现有的等效方法,但下面的方法应该有效:

public static <Outer, Inner, Key, Result> Stream<Result> join(
        Stream<Outer> outer, Stream<Inner> inner,
        Function<Outer, Key> outerKeyFunc,
        Function<Inner, Key> innerKeyFunc,
        BiFunction<Outer, Inner, Result> resultFunc) {

    //Collect the Inner values into a list as we'll need them repeatedly
    List<Inner> innerList = inner.collect(Collectors.toList());

    //matches will store the matches between inner and outer
    final Map<Outer, List<Inner>> matches = new HashMap<>();

    //results will be used to collect the results in
    final List<Result> results = new ArrayList<>();


    outer.forEach(o -> innerList
            .stream()
            //Filter to get those Inners for which the Key equals the Key of this Outer
            .filter(i -> innerKeyFunc.apply(i).equals(outerKeyFunc.apply(o)))
            .forEach(i -> {
                if (matches.containsKey(o)) {
                    //This Outer already had matches, so add this Inner to the List
                    matches.get(o).add(i);
                } else {
                    //This is the first Inner to match this Outer, so create a List
                    List<Inner> list = new ArrayList<>();
                    list.add(i);
                    matches.put(o, list);
                }
            }));

    matches.forEach((out, in) -> in.stream()
            //Map each (Outer, Inner) pair to the appropriate Result...
            .map(i -> resultFunc.apply(out, i))
            //...and collect them
            .forEach(res -> results.add(res)));

    //Return the result as a Stream, like the .NET method does (IEnumerable)
    return results.stream();
}
当然,还需要进行更深入的测试,但我相信这种实现是正确的。它也可能更有效,我愿意接受建议。

。考虑这个例子:

List<Integer> l1 = Arrays.asList(1, 2, 3, 4);
List<Integer> l2 = Arrays.asList(2, 2, 4, 7);

l1.stream()
  .flatMap(i1 -> l2.stream()
                   .filter(i2 -> i1.equals(i2)))
  .forEach(System.out::println);
在上面的示例中,
flatMap()
对应于
(内部)JOIN
,而嵌套流的
filter()
操作对应于
ON
子句

是一个库,它实现了
innerJoin()
和其他连接类型,以便在此基础上进行抽象,例如,如果要连接两个
实例,而不是两个
集合
实例,还可以缓冲流内容。用jOOλ,你会写:

Seq<Integer> s1 = Seq.of(1, 2, 3, 4);
Seq<Integer> s2 = Seq.of(2, 2, 4, 7);

s1.innerJoin(s2, (i1, i2) -> i1.equals(i2))
  .forEach(System.out::println);
(免责声明,我为jOOλ背后的公司工作)

我也来自C#,错过了这个功能。一个很大的优势是通过表达意图来获得可读的代码。所以我写了自己的,它的工作原理类似于C#Enumerable.Join()。另外:它允许空键

Stream<BestFriends> bestFriends = 
 join(listOfPersons.stream())
  .withKey(Person::getName)
  .on(listOfDogs.stream())
  .withKey(Dog::getOwnerName)
  .combine((person, dog) -> new BestFriends(person, dog))
  .asStream();
streambestfriends=
join(listOfPersons.stream())
.withKey(Person::getName)
.on(listOfDogs.stream())
.withKey(狗::getOwnerName)
.combine((人,狗)->新好友(人,狗))
.asStream();

几乎可以肯定,您必须将两个流都转储到指定键上的映射中,然后直接加入映射。Java流实际上不是以任何方式组合的,而是连接。
2
2
4
Seq<Integer> s1 = Seq.of(1, 2, 3, 4);
Seq<Integer> s2 = Seq.of(2, 2, 4, 7);

s1.innerJoin(s2, (i1, i2) -> i1.equals(i2))
  .forEach(System.out::println);
(2, 2)
(2, 2)
(4, 4)
Stream<BestFriends> bestFriends = 
 join(listOfPersons.stream())
  .withKey(Person::getName)
  .on(listOfDogs.stream())
  .withKey(Dog::getOwnerName)
  .combine((person, dog) -> new BestFriends(person, dog))
  .asStream();