Java流:如何按关键字分组?
我有一个文本文件,看起来像Java流:如何按关键字分组?,java,java-stream,Java,Java Stream,我有一个文本文件,看起来像 Group: A 12 27 14 Group: B 68 10 42 79 Group: D ... 我想计算每组数字列表的统计数据 问题:有没有一种好的方法可以用Java流实现这一点 注意:我知道,给定一个IntStream,可以通过应用方法summaryStatistics获得统计信息。我的问题是,我不知道如何将关键字“group:”下面的元素分组 补充:关于有些奇怪的评论:没有流,问题可以通过 String group = null;
Group: A
12
27
14
Group: B
68
10
42
79
Group: D
...
我想计算每组数字列表的统计数据
问题:有没有一种好的方法可以用Java流实现这一点
注意:我知道,给定一个IntStream
,可以通过应用方法summaryStatistics
获得统计信息。我的问题是,我不知道如何将关键字“group:”下面的元素分组
补充:关于有些奇怪的评论:没有流,问题可以通过
String group = null;
boolean first = true;
List<String> lines = Files.readAllLines(path);
for (String s: lines) {
if (s.startsWith("Group:") {
if (!first) {
System.out.println(group + " sum: " + sum);
}
first = false;
group = s;
sum = 0;
} else {
sum += Integer.parseInt(s.strip());
}
}
System.out.println(group + " sum: " + sum);
字符串组=null;
布尔值优先=真;
列表行=文件。readAllLines(路径);
对于(字符串s:行){
如果(s.startsWith(“组:”){
如果(!first){
System.out.println(组+“总和:”+sum);
}
第一个=假;
组=s;
总和=0;
}否则{
sum+=Integer.parseInt(s.strip());
}
}
System.out.println(组+“总和:”+sum);
试试这个。我把数据放在一个数组中进行演示
String[] vals = {
"Group: A ",
"12 ",
"27 ",
"14 ",
"Group: B ",
"68 ",
"10 ",
"42 ",
"79 ",
"Group: D ",
"10 ",
"20 ",
"30 ",
"18 ",
"12 "
};
在映射中对数据进行分组很简单,只需捕获组
标记,然后将值添加到该标记的列表
值中。在处理之前,数据会被删除空白,并将适当的字符串转换为整数。
由于数据的异步性,我想不出一种更简洁的方法,其他人可能会有更好的想法
Map<String, List<Integer>> map = new HashMap<>();
List<Integer> numbs = null;
for (String v : vals) {
v = v.trim();
if (v.startsWith("Group")) {
// add a new List and save its reference
map.put(v, numbs = new ArrayList<>());
} else {
// add using current object
numbs.add(Integer.valueOf(v));
}
}
如上所述,流不适用于有状态操作。但是,串行处理可以将每组的多行转换为每组一行,因此(src/temp.txt
):
变成这样:
Group:A 12 27 14
Group:B 68 10 42 79
Group:D 98 187 894 67
Group:G 3 3
Group:G 5 5
在String
的列表中,通过在每个组前面添加换行符:X
,修剪所有空格,然后连接所有字符串。然后,您可以以无状态方式流式处理列表,并将每个组映射到IntSummaryStatistics
:
import java.util.List;
导入java.util.Map;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
导入java.util.IntSummaryStatistics;
导入java.nio.file.Files;
导入java.nio.file.Path;
导入java.io.IOException;
公共类堆栈溢出测试{
公共静态void main(字符串[]args){
Path Path=Path.of(“src/temp.txt”);
试一试{
//通过向匹配组特征的字符串添加换行符来转换字符串
列表转换=
Files.readAllLines(路径)
.stream()
.map(s->s.matches(“^[a-zA-Z]*:*”)?
“\n”+s.replace(“,”):s.trim())
.collect(collector.joining(“”)//一个长字符串
.lines()//根据换行符拆分
.skip(1)//不需要第一个空行
.collect(Collectors.toList());
System.out.println(“转换列表:\n”+转换);
System.out.println();
//使用各自的IntSummaryStatistics将转换后的列表映射到各个组
地图摘要=
转化
.stream()
.map(s->s.split(\\s”))
.collect(Collectors.toMap(s->s[0],//第一个索引是组
s->IntStream.range(1,s.length)
.map(i->Integer.parseInt(s[i]))
.summaryStatistics(),
(a,b)->{a.combine(b);返回a;}
)
);
System.out.println(“映射统计信息:\n”+mapSummary);
}捕获(IOEX异常){
System.out.println(“Oops:+ex”);
}
}
}
结果(被添加的换行符欺骗):
这需要一个有状态函子。我会在collect()中使用一个
ing,但我不记得有状态函子在流API中是否合法。为什么使用downvote?实践中有许多类似的文本文件。正如所解释的,使用循环写下解决方案是很简单的。但我希望有一个更简单的流解决方案。这就是问题的原因,这个原因显然是错误的在标题(“Java stream”)和问题(“使用Java streams执行此操作”)。根据这一点,函子需要是无状态的,也就是说,在我看来,不能仅使用流。您可能需要首先使用普通循环(或其他库)将映射中的元素分组,然后对条目进行流式处理。
Group: A=IntSummaryStatistics{count=3, sum=53, min=12, average=17.666667, max=27}
Group: B=IntSummaryStatistics{count=4, sum=199, min=10, average=49.750000, max=79}
Group: D=IntSummaryStatistics{count=5, sum=90, min=10, average=18.000000, max=30}
Group: A
12
27
14
Group: B
68
10
42
79
Group: D
98
187
894
67
Group: G
3
3
Group: G
5
5
Group:A 12 27 14
Group:B 68 10 42 79
Group:D 98 187 894 67
Group:G 3 3
Group:G 5 5
Transformed list:
[Group:A 12 27 14 , Group:B 68 10 42 79 , Group:D 98 187 894 67 , Group:G 3 3 , Group:G 5 5]
Mapping statistics:
{
Group:B=IntSummaryStatistics{count=4, sum=199, min=10, average=49.750000, max=79},
Group:A=IntSummaryStatistics{count=3, sum=53, min=12, average=17.666667, max=27},
Group:G=IntSummaryStatistics{count=4, sum=16, min=3, average=4.000000, max=5},
Group:D=IntSummaryStatistics{count=4, sum=1246, min=67, average=311.500000, max=894}
}