1

我有一个HashMap<String, List<Appliance>>wherename::String对象中的字段Appliance用作键,并且每个值都是HashMap一个对象。每个列表都根据对象的字段“price::BigDecimal”按升序排序。我想创建一个, 使用, 并通过提取先存在于 中的每个列表的第一个元素,然后是第二个元素,等等。所以如果有这些内容:listApplianceApplianceArrayList<Appliance>Stream APIHashMapHashMapHashMap

["Fridge",     [<"Fridge", 100>, <"Fridge", 200>, <"Fridge", 300>],
 "Oven",       [<"Oven", 150>, <"Oven", 250>, <"Oven", 350>],
 "DishWasher", [<"DishWasher", 220>, <"DishWasher", 320>, <"DishWasher", 420>]]

我希望最终名单如下:

[<"Fridge",     100>,
 <"Oven",       150>,
 <"DishWasher", 220>,
 <"Fridge",     200>,
 <"Oven",       250>,
 <"DishWasher", 320>,
 <"Fridge",     300>,
 <"Oven",       350>,
 <"DishWasher", 420>]

是否可以使用 Java 的 8 Stream API 以功能方式做到这一点?

这是我的代码。我想以声明的方式实现相同的结果。

while(!appliancesMap.isEmpty()) {
    for (Map.Entry<String, List<Appliance>> entry : 
        appliancesMap.entrySet()) {
        String key = entry.getKey();
        List<Appliance> value = entry.getValue();
        finalList.add(value.get(0));
        value.remove(0);
        if (value.size() == 0) {
            appliancesMap.entrySet()
                .removeIf(predicate -> predicate.getKey().equals(key));
        } else {
            appliancesMap.replace(key, value);
        }
    }
}
4

3 回答 3

1

脚步:

  1. 查找地图内最长列表的大小。这可以作为
map.keySet().stream().mapToInt(k -> map.get(k).size()).max().getAsInt()
  1. 使用 anIntStream迭代从 0 到步骤#1 中获得的最大大小的值
IntStream.range(0, map.keySet().stream().mapToInt(k -> map.get(k).size()).max().getAsInt())
  1. 使用 的每个值(例如iIntStream作为索引从列表中获取元素,例如 if i = 00从地图内的每个列表中获取索引处的元素并添加到result列表
List<Appliance> result = new ArrayList<>();

IntStream.range(0, map.keySet().stream().mapToInt(k -> map.get(k).size()).max().getAsInt())
    .forEach(i -> map
                .keySet()
                .stream()
                .filter(key -> i < map.get(key).size())
                .forEach(k -> result.add(map.get(k).get(i))));

演示

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

class Appliance {
    private String name;
    private double price;

    public Appliance(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Appliance [name=" + name + ", price=" + price + "]";
    }
}

public class Main {
    public static void main(String[] args) {
        Map<String, List<Appliance>> map = Map.of("Fridge",
                List.of(new Appliance("Fridge", 100), new Appliance("Fridge", 200), new Appliance("Fridge", 300)),
                "Oven", List.of(new Appliance("Oven", 150), new Appliance("Oven", 250), new Appliance("Oven", 350)),
                "DishWasher", List.of(new Appliance("DishWasher", 220), new Appliance("DishWasher", 320),
                        new Appliance("DishWasher", 420)));

        List<Appliance> result = new ArrayList<>();

        IntStream.range(0, map.keySet().stream().mapToInt(k -> map.get(k).size()).max().getAsInt())
        .forEach(i -> map
                .keySet()
                .stream()
                .filter(key -> i < map.get(key).size())
                .forEach(k -> result.add(map.get(k).get(i))));

        // Display
        result.forEach(System.out::println);
    }
}

输出:

Appliance [name=Fridge, price=100.0]
Appliance [name=Oven, price=150.0]
Appliance [name=DishWasher, price=220.0]
Appliance [name=Fridge, price=200.0]
Appliance [name=Oven, price=250.0]
Appliance [name=DishWasher, price=320.0]
Appliance [name=Fridge, price=300.0]
Appliance [name=Oven, price=350.0]
Appliance [name=DishWasher, price=420.0]

[更新]

下面给出了解决方案的惯用代码(感谢Holger):

List<Appliance> result = IntStream.range(0, map.values().stream().mapToInt(List::size).max().getAsInt())
                            .mapToObj(i -> map.values()
                                    .stream()
                                    .filter(list -> i < list.size())
                                    .map(list -> list.get(i)))
                            .flatMap(Function.identity()).collect(Collectors.toList());
于 2020-05-15T01:27:57.553 回答
0

如果您不介意订单Fridge -> Oven -> DishWasher,以下代码很有帮助:

map.values().stream().flatMap((Function<List<Appliance>, Stream<Appliance>>) Collection::stream)
    .collect(Collectors.groupingBy(appliance -> {
    List<Appliance> appliances = map.get(appliance.getName());
    for (int i = 0;i<appliances.size();i++) {
        if (appliance.getPrice() == appliances.get(i).getPrice()) {
            return i;
        }
    }
    return 0;
})).values().stream().flatMap((Function<List<Appliance>, Stream<Appliance>>) Collection::stream)
    .forEach(System.out::println);
于 2020-05-15T01:46:50.387 回答
0
map.keySet().stream().map(map::get).forEach(list::addAll);

.addAll()在一个.stream()可以做的工作。

现在您已经拥有列表中的所有元素,您可以对其进行排序:

list.sort(Comparator.comparing(Object::toString)
    .thenComparingInt(s -> Integer.parseInt(
            s.toString()
             .substring(0, s.toString().length() - 1)
             .split(",")[1].trim())));
于 2020-05-14T22:11:56.773 回答