【问题标题】:Open stream inside a stream在流中打开流
【发布时间】:2018-05-25 15:49:32
【问题描述】:

我有这段代码。我怎样才能改变它? 功能风格?事实上,我有List<X>。每个 X 包含List<V>。此列表中的每个 V 都有 List<M> 作为参数。我需要构建Map<X,Y>,其中 Y 是存储在对象 X 中聚合的所有 V 对象中的所有 M 对象的数量。

HashMap<Country, Integer> modelsPerCountryMap = new HashMap<>();
int count;
for (Country country : CountryDataSingleton.getCountryDataCollection()) {
    count = 0;
    for (CarMaker cm : country.getListOfMakers()) {
        count += cm.getModels().size();
    }
    modelsPerCountryMap.put(country, count);
}

【问题讨论】:

  • 你可以用流替换你的代码,但老实说我不认为你应该这样做。这很清楚,而且流有开销。
  • 另外,您对列表内容的描述不清楚。是List&lt;List&lt;Pojo&gt;&gt;,其中Pojo 有一个字段List&lt;Model&gt;

标签: java java-8 functional-programming java-stream


【解决方案1】:

我会流式传输国家/地区,然后将它们收集到地图上,其中键是国家,值可以是制造商规模的总和:

Map<Country, Integer> modelsPerCountryMap =
     CountryDataSingleton.getCountryDataCollection()
                         .stream()
                         .collect(
                             Collectors.toMap(
                                 Function.identity(),
                                 c -> c.getListOfMakers()
                                       .stream()
                                       .mapToInt(cm -> cm.getModels().size())
                                       .sum()
                              )
                         );

【讨论】:

  • Function.identity() 而不是 indentity() ?
  • @Timir 是的,这是我这边的一个错字 - 感谢您的注意!已编辑和修复。
【解决方案2】:

这样的事情怎么样:

公共类 CountryFunctionalTest {

private class CarMaker {

    private final String name;
    private final List<String> models;

    public CarMaker(String name, List<String> models) {
        this.name = name;
        this.models = models;
    }

    public String getName() {
        return name;
    }

    public List<String> getModels() {
        return models;
    }
}

private class Country {

    private final String name;
    private final List<CarMaker> makers;

    public Country(String name, List<CarMaker> makers) {
        this.name = name;
        this.makers = makers;
    }

    public String getName() {
        return name;
    }

    public List<CarMaker> getMakers() {
        return makers;
    }
}

@Test
public void test() throws DeliveryException {
    List<Country> countries = Arrays.asList(new Country[]{
            new Country("Country A", Arrays.asList(new CarMaker[]{ new CarMaker("Maker A", Arrays.asList(new String [] {"model a", "model a1", "model a2"})) })),
            new Country("Country B", Arrays.asList(new CarMaker[]{ new CarMaker("Maker B", Arrays.asList(new String [] {"model b", "model b1"})) })),
            new Country("Country C", Arrays.asList(new CarMaker[]{ new CarMaker("Maker C", Arrays.asList(new String [] {"model c", "model c1", "model c2", "model c3"})) }))
    });

    Map<Country, Integer> conuntriesModels = IntStream.range(0, countries.size()).mapToObj(i -> new AbstractMap.SimpleEntry<Country, Integer>(countries.get(i),
            IntStream.range(0, countries.get(i).getMakers().size())
                .map(ix -> countries.get(i).getMakers().get(ix).getModels().size()).sum()
                )
            ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    for (Country next : conuntriesModels.keySet()) {
        System.out.println(next.getName() + " models -> " + conuntriesModels.get(next));
    }
}

}

输出:

国家 B 型号 -> 2

A 国型号 -> 3

C 国型号 -> 4

【讨论】:

  • 太可怕了。
【解决方案3】:

如果您打算在 java 中使用函数,请考虑使用vavr.io。 Vavr 为您提供了以方便一致 方式应用函数式范例所需的工具。在这种情况下不可变数据结构。使用io.vavr.collection.Streamio.vavr.collection.HashMap,将您的数据收集到Map&lt;Country, Integer&gt; 可能看起来像这样:

Stream.ofAll(CountryDataSingleton.getCountryDataCollection())
        .map(country -> Tuple.of(country, country.getListOfMakers().foldLeft(0, (acc, cm) -> acc + cm.getModels().size())))
        .foldLeft(HashMap.<Country, Integer>empty(), (acc, entry) -> acc.put(entry));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 2017-03-01
    • 1970-01-01
    相关资源
    最近更新 更多