【问题标题】:Stream, Map, Reduce... how is it done?Stream、Map、Reduce……它是怎么做的?
【发布时间】:2014-08-03 14:13:17
【问题描述】:

我正在尝试深入研究 Java 8 流,但时不时仍会卡住。我目前有一个问题,我知道它可以通过流来完成,但我似乎无法理解如何正确使用它们。

我有一个字符串 A 的列表,并尝试通过某个规则找到与 A 的另一个元素 b 匹配的 A 的所有元素 a,然后从中创建一个 Map<String, List<String>>,其中包含所有 a -> 所有匹配的 b。

详细说明:

  • 对于 A 中的每个 a,使用谓词 P 与 A 中的每个 b 进行比较。
  • 如果 P(a,b) 匹配,则从 a 和 b 生成一对 (x, y)。
  • 将所有对按 x 分组并作为地图返回。

你能给我一个有效的 Java 8 流示例吗?

编辑:我将如何以不必要的昂贵方式做到这一点:

Pairs(x,y) = forEach(a,b in A) 
  where (a != b && P(a, b)) 
  generatePairXY(a, b)
Map(x -> List(y)) = group(Pairs(x,y)) by x

这种方法的问题是我首先需要构建一个巨大的对列表,考虑到我的数百万字数据集,这可能会耗尽内存。

【问题讨论】:

  • 您基本上是在创建等价组。您的方法将导致每个组的 N 倍重复,其中 N 是组大小。如果您可以改为定义一个判别器函数,它为每个组生成一个唯一值,那么您的算法的复杂性将大大降低。
  • 我很想看看你的想法的工作代码示例。
  • 定义了鉴别器函数,这将是一个简单的collect(groupingBy(discriminatorFn)) 操作。当然,函数的定义取决于你。
  • 我仍然难以理解所有这些高级流函数,这就是我问这个问题的原因。可悲的是,我的想法只是通过例子来工作。

标签: java mapreduce java-8 java-stream


【解决方案1】:
List<String> list = ...;
Map<String, List<String>> map = 
  list.stream()
      .collect(Collectors.toMap(a -> a, a -> list.stream()
                                                 .filter(b -> P(a,b))
                                                 .collect(Collectors.toList()))
               );

这个想法是为原始列表的每个字符串创建一个映射,其中一个值是与该键匹配的所有字符串的过滤列表。

编辑:

这是一个完整的工作示例,如果两个字符串不相等但长度相同,则谓词 P 返回 true:

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test
{

  public static boolean P (String a, String b)
  {
    return a.length() == b.length() && !a.equals(b);
  }

  public static void main (String[] args)
  {
    List<String> list = new ArrayList<String>();
    list.add ("aaa");
    list.add ("bbb");
    list.add ("ccc");
    list.add ("cccc");
    list.add ("dddd");
    list.add ("ddd");

    Map<String, List<String>> map = 
      list.stream()
          .collect(Collectors.toMap(a -> a, a -> list.stream()
                                                     .filter(b -> P(a,b))
                                                     .collect(Collectors.toList()))
               );
    for (String key : map.keySet ()) {
      System.out.print (key + ": " );
      for (String value : map.get(key)) {
        System.out.print (value+ " ");
      }
      System.out.println("");
    }
  }

}

输出:

aaa: bbb ccc ddd
ccc: aaa bbb ddd
bbb: aaa ccc ddd
ddd: aaa bbb ccc
dddd: cccc
cccc: dddd

【讨论】:

  • 问题是第一个参数的a不能作为第二个参数P(a, b)的变量
  • @TwoThe 我修复并测试了代码。请参阅随附的工作示例。
猜你喜欢
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 2012-04-10
  • 2019-03-12
  • 2011-07-05
  • 2020-01-20
  • 2014-11-04
  • 1970-01-01
相关资源
最近更新 更多