2017-09-22 28 views
2

我有行的文件,以下列标题:的Java 8流:在总和值的不同键

CITY_NAME COUNTY_NAME POPULATION 

Atascocita Harris 65844 
Austin Travis 931820 
Baytown Harris 76335 
... 

我使用流以尝试产生类似的输出:

COUNTY_NAME CITIES_IN_COUNTY POPULATION_OF_COUNTY 
Harris 2 142179 
Travis 1 931820 
... 

到目前为止,我已经能够使用流获取不同县名的列表(因为这些是重复的),但是现在我遇到了在一个不同的县获得城市数量的问题,并因此导致了人口总数这些县的城市。我已阅读文件到类型texasCitiesClass的ArrayList,和我的代码到目前为止看起来像:

public static void main(String[] args) throws FileNotFoundException, IOException { 
    PrintStream output = new PrintStream(new File("output.txt")); 
    ArrayList<texasCitiesClass> txcArray = new ArrayList<texasCitiesClass>(); 
    initTheArray(txcArray); // this method will read the input file and populate an arraylist 
    System.setOut(output); 

    List<String> counties; 
    counties = txcArray.stream() 
      .filter(distinctByKey(txc -> txc.getCounty())) // grab distinct county names 
      .distinct() // redundant? 
      .sorted((txc1, txc2) -> txc1.getCounty().compareTo(txc2.getCounty())); // sort alphabetically 

} 

public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { 
    Map<Object, String> seen = new ConcurrentHashMap<>(); 
    return t -> seen.put(keyExtractor.apply(t), "") == null; 
}  

在这一点上,我有一个包含唯一的县名称的流。由于sorted()运算符将返回一个新的流,因此我如何获得(并因此求和)各个县的人口值?

+0

这段代码是否可以编译? '县'是列表? – nullpointer

+0

你的意思是'Map counties = txcArray.stream().collect(Collectors.groupingBy(txc - > txc.getCounty(),Collectors.counting()));'? – Holger

回答

1

鉴于类(构造函数,吸气,二传手省略)

class Foo { 
    String name; 
    String countyName; 
    int pop; 
} 

class Aggregate { 
     String name; 
     int count; 
     int pop; 
} 

您可以通过使用Collectors.toMap它们映射到聚合对象和使用其mergeFunction合并它们聚集你的价值观。使用TreeMap,它的条目按其关键字排序。

TreeMap<String, Aggregate> collect = foos.stream() 
     .collect(Collectors.toMap(
       Foo::getCountyName, 
       foo -> new Aggregate(foo.countyName,1,foo.pop), 
       (a, b) -> new Aggregate(b.name, a.count + 1, a.pop + b.pop), 
       TreeMap::new) 
     ); 

使用

List<Foo> foos = List.of(
     new Foo("A", "Harris", 44), 
     new Foo("C", "Travis ", 99), 
     new Foo("B", "Harris", 66) 
); 

地图是

{哈里斯=骨料{名称= '哈里斯',计数= 2,弹出= 110},特拉维斯=骨料{名称= 'Travis',count = 1,pop = 99}}

+1

您可以简单地使用Map counties = foos.stream().collect(Collectors.groupingBy(foo - > foo.countyName,TreeMap :: new,Collectors.summarizingInt(foo - > foo.pop)) );'无需额外的'Aggregate'类即可获得所有信息,因为'IntSummaryStatistics'同时包含count和sum。 – Holger

+0

@霍尔格:是的,但如果有多个价值积累... – user140547