微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 HashMaps 将总值和平均值映射到一个键

如何解决使用 HashMaps 将总值和平均值映射到一个键

我有一个 Country 类,并从 .csv 文件中读取了数据,该文件包含许多国家名称、它们所在的地区、每个国家的人口、地区等,并将其存储在 ArrayList 中。我主要使用 java 集合框架进行数据分析,并希望找到每个区域的总人口平均人口

我认为使用 HashMap 是最好的,但我不知道如何解决这个问题,因为我以前从未以任何复杂的方式或对象使用过。我也知道我必须将 int 的数据类型更改为总人口的 long。

public class Country {
    

    private String name;
    private String region;
    private int population;
    private int area;
    private double density;

    /**
     * Default constructor
     */
    public Country() {

    }

    /**
     * Creates a country with all args
     * 
     * @param name
     * @param region
     * @param population
     * @param area
     * @param density
     */
    public Country(String name,String region,int population,int area,double density) {
        super();
        this.name = name;
        this.region = region;
        this.population = population;
        this.area = area;
        this.density = density;
    }

/**
     * @return the region
     */
    public String getRegion() {
        return region;
    }

    /**
     * @param region the region to set
     */
    public void setRegion(String region) {
        this.region = region;
    }

/**
     * @return the population
     */
    public int getPopulation() {
        return population;
    }

    /**
     * @param population the population to set
     */
    public void setPopulation(int population) {
        this.population = population;
    }



public static void totalPopulationByRegion(Collection<Country> countries) {
        Map<String,Integer> map = new HashMap<String,Integer>();

        int total = 0;

        for (Country country : countries) {
            if (map.containsKey(country.getRegion())) {
                map.put(country.getRegion(),total);
                total+=country.getPopulation();
            } else
                map.put(country.getRegion(),total);
        }

        for (Map.Entry m : map.entrySet()) {
            System.out.println(m.getKey() + " " + m.getValue());
        }
    }

从控制台上的输出中,我意识到我的数学逻辑在这方面完全错误,甚至考虑到我没有处理过大而无法存储为 int 的数字这一事实。我没有得到我想要的密钥的重复项,我只是不知道如何获得映射到每个区域的人口的累计总数。对此的任何帮助将不胜感激。

从主方法调用时得到的输出


Near east 41843152
Asia -478957430
Europe -7912568
Africa 54079957
Latin amer. & carib 17926472
northern america -35219702
Baltics -1102504495
Oceania -616300040

来自 csv 文件的示例:

Country,Region,Population,Area (sq. mi.)
Afghanistan,ASIA,31056997,647500
Albania,EASTERN EUROPE,3581655,28748
Algeria,norTHERN AFRICA,32930091,2381740
American Samoa,OCEANIA,57794,199
Andorra,WESTERN EUROPE,71201,468
Angola,SUB-SAHaraN AFRICA,12127071,1246700
Anguilla,LATIN AMER. & CARIB,13477,102
Antigua & Barbuda,69108,443
Argentina,39921833,2766890

解决方法

如果您只想将区域与其总人口分组,那么您需要稍微修改您的代码。变量 total 应在您的 for 循环内声明,并应使用国家/地区的人口进行初始化。

public static void totalPopulationByRegion(Collection<Country> countries) {
        Map</*Region*/ String,/*Population*/ Long> map = new HashMap<>();

        for (Country country : countries) {
            long total = country.getPopulation();
            if (map.containsKey(country.getRegion())) {
                total+=country.getPopulation();
            }
            map.put(country.getRegion(),total);
        }

        for (Map.Entry m : map.entrySet()) {
            System.out.println(m.getKey() + " " + m.getValue());
        }
    }

但是,如果您希望对数据有更多的处理,那么如果您按区域和 Country 本身分组并缓存它以备将来使用这样的东西会更容易:

Map<String,List<Country>> groupData(Collection<Country> countries) {
        Map</*Region*/String,List<Country>> map = new HashMap<>();

        for (Country country : countries) {
            List<Country> regionCountries = new ArrayList<>();
            if (map.containsKey(country.getRegion())) {
                regionCountries = map.get(country.getRegion());
            }
            regionCountries.add(country);
            map.put(country.getRegion(),regionCountries);
        }
        return map;
    }

然后此 data 可用于汇总每个区域的总人口和平均人口,如下所示(为方便起见,我使用的是 Java 8 Stream API):

Map<String,Integer> getTotalPopulationPerRegion(Map<String,List<Country>> data) {
        Map<String,Integer> result = data.entrySet()
                .stream()
                .collect(Collectors.toMap(entry -> entry.getKey(),entry -> entry.getValue().stream().mapToInt(country -> country.getPopulation()).sum()));
        return result;
    }

Map<String,Double> getAveragePopulationPerRegion(Map<String,Double> result = data.entrySet()
                .stream()
                .collect(Collectors.toMap(entry -> entry.getKey(),entry -> entry.getValue().stream().mapToDouble(country -> country.getPopulation()).average().orElse(Double.NaN)));
        return result;
    }
,

假设你已经在你的country类中将population类型从int改为long

public static class Country {
    private String name;
    private String region;
    private long population;
    ...
}

以下是实现您所需要的一些方法:

public static void totalPopulationByRegion(Collection<Country> countries) {
    Map<String,Long> map = new HashMap<>();

    for (Country country : countries) {
        if (map.containsKey(country.getRegion())) {
            //if the map contains the region get the value and add the population of current country
            map.put(country.getRegion(),map.get(country.getRegion()) + country.getPopulation());
        } else{
            //else just put region of current country and population into the map
            map.put(country.getRegion(),country.getPopulation());
        }
    }

    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + " " + m.getValue());
    }
}

如果您使用的是 Java 8 或更高版本,可以使用 Map#computeIfPresentMap#computeIfAbsent 缩短上述内容并避免 if else 块

public static void totalPopulationByRegion2(Collection<Country> countries) {
    Map<String,Long> map = new HashMap<>();

    for (Country country : countries) {
        map.computeIfPresent(country.getRegion(),(reg,pop)->  pop + country.getPopulation());
        map.computeIfAbsent(country.getRegion(),reg -> country.getPopulation());                   
    }

    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + " " + m.getValue());
    }
}

使用流 API,创建地图的任务可以使用 Collectors#groupingByCollectors#summingLong

public static void totalPopulationByRegion3(Collection<Country> countries) {
    Map<String,Long> map = 
            countries.stream()
                     .collect(Collectors.groupingBy(Country::getRegion,Collectors.summingLong(Country::getPopulation)));

    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + " " + m.getValue());
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。