【问题标题】:Conditional groupingBy: advanced Java Streams条件分组依据:高级 Java 流
【发布时间】:2021-11-14 14:46:04
【问题描述】:

我有一个任务,我想只用流来完成,本质上它是对对象列表的复杂分组操作。让我们假设下表是一个对象列表(列是对象的成员)。

A B C D E F G H I
obj 1 j k k l m o q 6 t
obj 2 j k k l m o q 8 t
obj 3 j k k l m o u 8 t
obj 4 a a a a m a a a t

我首先需要按 A、B、C、D、I 分组。简单。

data.stream()
    .collect(Collectors.groupingBy(A + B + C + D + I)

组1

A B C D E F G H I
obj 1 j k k l m o q 6 t
obj 2 j k k l m o q 8 t
obj 3 j k k l m o u 8 t

第 2 组

A B C D E F G H I
obj 4 a a a a m a a a t

然后,如果生成的映射具有列 E 具有重复值的组,即组 1(obj 1、2,3 中的重复值 m)。我需要查看FG 列。对于 F 具有所有相同值且 G 具有所有相同值的所有行,我需要将 H 列中的值相加,然后合并这些行。如果值不同,我需要保持原样并创建一个新组。我不能只按 F 列分组,因为如果组中没有重复的元素,我希望它们留在同一个组中。如果列 m 具有所有不同的值,则不会发生“次要”分组。上表的结果是

组1

A B C D E F G H I
obj 1 j k k l m o q 14 t

第 2 组

A B C D E F G H I
obj 3 j k k l m o u 8 t

第三组

A B C D E F G H I
obj 4 a a a a m a q a t

我的一部分人认为这对于流是不可能的,我应该减少损失,但也不太精通 Java 流。感谢您的帮助。

【问题讨论】:

  • 显示你编写的没有流的代码。这将消除您的要求并证明基于流的实现的正确性。此外,请记住,流只是提高可读性的一种工具——除了最简单的应用程序之外,这种优点很快就会在所有应用程序中消失。
  • 例如字段 H 已求和,但您未指定字段 I 的减少。
  • @erickson 在初始组中使用
  • 明白了。为什么不按 ABCDEFGI 分组,通过对 H 求和来合并重复项?
  • 您是否考虑过简单的嵌套循环或循环/流混合解决方案?伊莫,弄清楚这一点所花费的时间收益递减,结果可能不会像更简单的结构那样有效。

标签: java java-stream grouping


【解决方案1】:

根据您的描述,您应该能够通过 ABCDEFGI group 项目,然后通过对 H 求和 combine 任何具有重复键的项目。似乎不需要多个分组操作。

因为你没有提供任何代码,我只好编一个例子。我试图遵循您给出的粗略描述,同时减少这么多领域所需的重复。所提供的信息使我怀疑将这八个不同的关键字段组合到一个附加对象中可能会改进您的 API,并允许您将一些帮助程序代码合并到您的类中。

final class Key {

    static Collection<? extends YourClass> consolidate(Collection<? extends YourClass> items) {
        return items.stream()
            .collect(Collectors.groupingBy(Key::new, Collectors.reducing(null, Key::merge)))
            .values();
    }

    private final YourClass val;

    /**
     * @param val an instance of your class to be wrapped for testing equality of key fields
     */
    private Key(YourClass val) {this.val = val;}

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Key)) return false;
        YourClass that = ((Key) obj).val;
        return Objects.equals(val.a, that.a) && Objects.equals(val.b, that.b);
    }

    @Override
    public int hashCode() {
        return Objects.hash(val.a, val.b);
    }

    /**
     * @param o1 an instance of your class
     * @param o2 another instance of your class
     * @return an instance that representing the combination of {@code o1} and {@code o2}
     */
    private static YourClass merge(YourClass o1, YourClass o2) {
        if (o1 == null) return o2;
        if (o2 == null) return o1;
        if (!Objects.equals(o1.a, o2.a)) throw new IllegalArgumentException();
        if (!Objects.equals(o1.b, o2.b)) throw new IllegalArgumentException();
        return new YourClass(o1.a, o1.b, o1.h + o2.h);
    }

}

final class YourClass {
    final String a, b;
    final int h;
    YourClass(String a, String b, int h) {
        this.a = a;
        this.b = b;
        this.h = h;
    }
    @Override
    public String toString() {
        return a + ' ' + b + ": " + h;
    }
}

【讨论】:

    猜你喜欢
    • 2015-12-19
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多