【问题标题】:Flatmap nested collection平面图嵌套集合
【发布时间】:2019-06-27 12:15:25
【问题描述】:

我有一个对象列表,其中一些可以是集合。我想得到一个普通对象流。

List<Object> objects = List.of(1, 2, "SomeString", List.of(3, 4, 5, 6), 
    7, List.of("a", "b", "c"),
    List.of(8, List.of(9, List.of(10))));

我想获得一个带有元素的流。

1, 2, "SomeString", 3, 4, 5, 6, 7, "a", "b", "c", 8, 9, 10

我试过了

Function<Object, Stream<Object>> mbjectToStreamMapper = null; //define it. I have not figured it out yet!
objects.stream().flatMap(ObjectToStreamMapper).forEach(System.out::println);

我还检查了example,它展示了如何使用递归函数来展平集合。但是,在此示例中,.collect(Collectors.toList()); 用于保留中间结果。 Collectors.toList() 是一个终端操作,它将立即开始处理流。我想获得一个流,我可以稍后对其进行迭代。


更新

我同意 cmets,让一个由不同性质的对象组成的流是一个糟糕的主意。为了简单起见,我只是写了这个问题。在现实生活中,我可能会监听不同的事件,并处理来自传入流的一些业务对象,其中一些可以发送对象流,其他的 - 只是单个对象。

【问题讨论】:

  • "我有一个对象列表,其中一些可以是集合。"除非您的实际对象具有更有用的通用超类型,否则您实际上几乎无法使用此列表 - 无论流如何 - 没有某种反射。所以解决方案(几乎)不可避免地涉及反射。
  • 您确定需要将所有这些对象存储在同一个列表中吗?听起来对我来说是个可怕的想法
  • @LászlóStahorszki,是的,我同意你的看法。只是为了简单起见。例如,我需要处理事件,updatedEvents,complexEvents,它们来自不同的来源。正如我在更新中所写。
  • 我很确定你可以创建一个通用接口,所有列表成员都可以实现
  • 不要将这种混合物放在任何地方。而是将这些东西包装在一个对象中,该对象实现了一个包含流方法的通用接口。然后你有List&lt;MyStreamableThing&gt;,它更好,可以用objects.stream().flatMap(MyStreamableThing::toStream)处理。

标签: java java-stream flatmap


【解决方案1】:
class Loop {
    private static Stream<Object> flat(Object o) {
        return o instanceof Collection ?
                ((Collection) o).stream().flatMap(Loop::flat) : Stream.of(o);
    }

    public static void main(String[] args) {
        List<Object> objects = List.of(1, 2, "SomeString", List.of( 3, 4, 5, 6),
                7, List.of("a", "b", "c"), List.of(8, List.of(9, List.of(10))));

        List<Object> flat = flat(objects).collect(Collectors.toList());

        System.out.println(flat);
    }
}

请注意List.of(null) 抛出 NPE。

【讨论】:

    【解决方案2】:

    如果被遍历的对象是Collection 的实例,我们可以递归地得到嵌套的stream

    public static void main(String args[]) {
           List<Object> objects = List.of(1, 2, "SomeString", List.of(3, 4, 5, 6),
                7, List.of("a", "b", "c"),
                List.of(8, List.of(9, List.of(10))));
           List<Object> list = objects.stream().flatMap(c -> getNestedStream(c)).collect(Collectors.toList());
    }
    
    public static Stream<Object> getNestedStream(Object obj) {
        if(obj instanceof Collection){
            return ((Collection)obj).stream().flatMap((coll) -> getNestedStream(coll));
        }
        return Stream.of(obj);
    }
    

    【讨论】:

    • 这里不需要过滤,因为 List.of 不接受空参数。即使我将 List.of new ArrayList 与 null 一起传递,它也会起作用。
    • 如果obj 不是Collection 的实例,则不需要c
    【解决方案3】:

    注意,可以在字段中定义递归方法:

    public class Test {
      static Function<Object,Stream<?>> flat=
        s->s instanceof Collection ? ((Collection<?>)s).stream().flatMap(Test.flat) : Stream.of(s);
      public static void main(String[] args) {
        objects.stream().flatMap(flat).forEach(System.out::print);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-15
      • 2020-12-01
      • 1970-01-01
      • 2015-06-20
      • 1970-01-01
      • 2015-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多