使用流分组并对深层嵌套列表求和

时间:2016-04-22 17:00:02

标签: java

我有三个班级:

public class Supply {
    private final List<Compartment> compartments;

    public List<Compartment> getCompartments() {
        return compartments;
    }

    public Supply(List<Compartment> compartments) {
        this.compartments = compartments;
    }
}

public class Compartment {
    private final String itemId;
    private final List<Unit> units;

    public String getItemId() {
        return itemId;
    }

    public List<Unit> getUnits() {
        return units;
    }

    public Compartment(String itemId, List<Unit> units) {
        this.itemId = itemId;
        this.units = units;
    }
}

public class Unit {
    private final String containerNumber;

    public String getContainerNumber() {
        return containerNumber;
    }

    public Unit(String containerNumber) {
        this.containerNumber = containerNumber;
    }
}

鉴于这些课程,我想提出一个列表,地图,元组或类型:itemIdcontainerNumber 组合及其数量。

也就是说,如果我有:

Unit unit1 = new Unit("unit");
Unit unit2 = new Unit("unit");
Unit unit3 = new Unit("another_unit");

Compartment compartment = new Compartment("foo", newArrayList(unit1, unit2, unit3));

Supply supply = new Supply(newArrayList(compartment));

使用Java流,我希望得到类似的结果:

"foo", "unit", 2
"foo", "another_unit", 1

我已尝试过与groupingBytoMap等多种组合,没有这样的运气。

我最近的尝试是这样的:

Map<String, List<Map<String, List<Unit>>>> result = supply.getCompartments()
    .stream()
    .collect(groupingBy(Compartment::getItemId,
            mapping(compartment -> compartment.getUnits().stream().collect(groupingBy(Unit::getContainerNumber)), toList())));

我觉得非常接近,但我想我无法使用Map,因为密钥itemId可以多次使用不同的containerNumber

1 个答案:

答案 0 :(得分:1)

你有正确的想法。您缺少的是您需要一个平面映射收集器而不是映射收集器作为下游收集器。

可悲的是,这个收集器并没有内置在Java 8中,但它将出现在Java 9(JDK-8071600)中,Collectors.flatMapping(mapper, downstream)。对于Java 8,可以像这样重新实现它:

class UIStoryboardSegueFromTop: UIStoryboardSegue {
    override func perform() {
        let src = self.sourceViewController as UIViewController
        let dst = self.destinationViewController as UIViewController

        src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
        dst.view.transform = CGAffineTransformMakeTranslation(0, -src.view.frame.size.height)

        UIView.animateWithDuration(1.0, animations: {
            dst.view.transform = CGAffineTransformMakeTranslation(0, 0)

            }) { (Finished) in
                src.presentViewController(dst, animated: false, completion: nil)
        }
    }
}

然后你可以使用这个收集器来构建你想要的地图:

static <T,U,A,R> Collector<T,?,R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
    BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
    return Collector.of(
            downstream.supplier(),
            (acc, t) -> {
                try (Stream<? extends U> stream = mapper.apply(t)) {
                    if (stream != null) {
                        stream.sequential().forEach(u -> downstreamAccumulator.accept(acc, u));
                    }
                }
            },
            downstream.combiner(),
            downstream.finisher(),
            downstream.characteristics().toArray(new Characteristics[downstream.characteristics().size()])
           );
}