我无法使用流从字面上列出所有重复项

问题描述 投票:0回答:3

我有以下问题:

目标:我想要根据“名称”在列表中找到的所有重复项。

约束:我需要使用流。

错误:没有错误。

描述:

我有一个“城市”类的实例列表。 目标是有一个列表,其中包含所有基于“名称”找到的重复项,而不仅仅是一个,使用流。

我曾尝试研究我的问题的答案,但找到的所有答案都只解释了如何添加重复一次的元素,如果情况需要,则不会添加两次或三次。

我找到的研究资料:

Java 8, Streams 查找重复元素

https://mkyong.com/java8/java-8-find-duplicate-elements-in-a-stream/

再次目标:随着下面显示的列表,将创建一个新列表以接收重复项,其中包含“Lisboa”3x、“Braga”3x、“Guarda”2x,这是因为这些是基于重复元素在名字上。

我相信我已经向您提供了所有可能的细节,但是如果有任何遗漏,请告诉我。

谢谢。

主要:

public class Main {
    public static void main(String[] args) {
        List<City> portugalCities = List.of(
                new City("Lisboa", "Estremadura", 2275591),
                new City("Lisboa", "Estremadura", 2275591),
                new City("Faro", "Algarve", 67650),
                new City("Braga", "Minho", 193324),
                new City("Braga", "Esposende", 193324),
                new City("Braga", "Fafe", 193324),
                new City("Alentejo", "Ribatejo", 704533),
                new City("Viseu", "Beira Alta", 99561),
                new City("Lisboa", "Alenquer", 2275591),
                new City("Guarda", "Almeida", 143019),
                new City("Guarda", "Aguiar da Beira", 143019)
        );
    }
}

城市:

public class City {
    private String name;
    private String province;
    private int population;
    // ----- Properties

    public City(String name, String province, int population) {
        this.name = name;
        this.province = province;
        this.population = population;
    }
    // ----- Constructor

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String district) {
        this.province = district;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
    // ----- Getter & Setters

    @Override
    public String toString() {
        return String.format("|name: %s; district: %s; population: %s|", name, province, population);
    }
    // ----- toString

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        City city = (City) o;
        return population == city.population && Objects.equals(name, city.name) && Objects.equals(province, city.province);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, province, population);
    }

    // ----- Equals & hashCode
}
java stream
3个回答
0
投票

你会想要为此使用自定义收集器,与 https://mdn.io/Array.reduce:

这个例子产生输出:

{Alentejo=1, Braga=3, Faro=1, Guarda=2, Lisboa=3, Viseu=1}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collector;


public class Example {

    public static void main(String[] args) {

        List<City> portugalCities = List.of(
                new City("Lisboa", "Estremadura", 2275591),
                new City("Lisboa", "Estremadura", 2275591),
                new City("Faro", "Algarve", 67650),
                new City("Braga", "Minho", 193324),
                new City("Braga", "Esposende", 193324),
                new City("Braga", "Fafe", 193324),
                new City("Alentejo", "Ribatejo", 704533),
                new City("Viseu", "Beira Alta", 99561),
                new City("Lisboa", "Alenquer", 2275591),
                new City("Guarda", "Almeida", 143019),
                new City("Guarda", "Aguiar da Beira", 143019)
        );

        Map<String, Integer> counts = portugalCities.stream()
                .collect(Collector.<City, Map<String, Integer>>of(
                        // this means our collector starts by creating a tree map
                        // using the default constructor,
                        // which we passed here
                        TreeMap::new,
                        //
                        // then, process each element collecting to a map.
                        // basically:
                        // [{ name: 'a' }, { name: 'a' }, { name: 'b' }]
                        //  .reduce((acc /* accumulator*/, next) => {
                        //    acc[next.name] = (acc[next.name] || 0) + 1;
                        //    return acc; }, {} /* initial value of acc */)
                        (map, next) -> map.put(next.getName(),
                                map.computeIfAbsent(next.getName(), k -> 0) + 1),
                        // this is not needed, as you only have 1 map
                        // if given, it would be how to combine 2 maps (a, and b)
                        (a, b) -> {
                            throw new UnsupportedOperationException();
                        }
                ));

        System.out.println(counts);
    }

    @AllArgsConstructor
    @Accessors(chain = true)
    @Data
    static class City {
        private String name;
        private String province;
        private int population;
    }
}

0
投票

收集名字并计数,然后过滤掉非骗子:

List<Map.Entry<String, Long>> dupes = portugalCities.stream()
    .map(City::getName)
    .collect(groupingBy(n -> n, counting()))
    .entrySet().stream()
    .filter(e -> e.getValue() > 1)
    .collect(toList());

然后随意打印:

dupes.forEach(System.out::println);

输出:

Lisboa=3
Guarda=2
Braga=3

0
投票

理想情况下,流将一次处理一个元素,而无需存储中间结果。然而,在这种情况下,我们需要按名称分组存储城市,因为除非我们处理了所有元素,否则我们无法知道哪些是重复的。因此,鉴于类

City
的定义和问题的数据集,我提出以下两步过程:

Map<String, List<City>> citiesByName =
  portugalCities.stream().collect(Collectors.groupingBy(City::getName));
List<City> result =
  citiesByName.values().stream()
    .filter(list -> list.size() > 1)
    .flatMap(List::stream)
    .toList();

可以在更高级的单链中完成,但仍然有一个中间结果,

citiesByName
.

结果包含all duplicates(据我了解是问题的对象),而不仅仅是计数。

© www.soinside.com 2019 - 2024. All rights reserved.