我正在尝试使用Java 8流和lambda表达式从List<String> list
中仅提取数字。首先我要做的是从文件到列表加载字符串。之后我过滤流以获得包含“PL”的字符串。
我的档案:
Jan Kowalski PL 35000
Jiri Prohazka CZ 28000
Anna Malinowska PL 52000
Jozef Bak PL 49999
Helmut Schnittke DE 45000
Kleofas Oginski PL 45000
John Bull US 74000
Lukasz Zolw PL 9400
Franz Beckenbauer DE 83000
Frantisek Kupka CZ 32000
代码:
List<String> list = new ArrayList<>();
try (Stream<String> stream = Files.lines(Paths.get("file"),Charset.defaultCharset())) {
list = stream
.filter(line -> line.contains("PL"))
.peek(System.out::println)
.collect(Collectors.toList());
}
我认为现在最好的方法是删除字符串中的所有字母并仅留下小数,但我有问题该怎么办呢。 最后的结果应该让我将list的元素解析为整数,对它们进行排序,并获得前三个元素的总和。 我已经做到了,但我确信有更好的方法(例如只使用一个列表)
List<Integer> iList = new ArrayList<Integer>();
list.forEach(s->
{
s = s.replaceAll("\\D+","");
iList.add(Integer.parseInt(s));
});
Collections.sort(iList);
Collections.reverse(iList);
int sum = 0;
for(int i=0;i<3;i++){
sum=sum+iList.get(i);
}
任何想法如何在不使用任何其他列表的情况下完成?
答案 0 :(得分:4)
您可以在单个Stream管道中执行此操作。要提取号码,您可以使用Pattern
并为该号码创建capturing group。在这种情况下,模式将是"(\\d+)"
。
这是通过在Matcher
的帮助下创建Pattern.matcher(input)
,再次过滤实际包含Matcher.find()
的数字的行并使用Matcher.group(group)
提取捕获的数字来完成的。在这种情况下,数字是第一个捕获的元素,因此它在组1中。
此流转换为带Stream<Integer>
的Stream.map(mapper)
:此处的映射器是返回从每行解析的Integer
值的函数。最后,为了对三个最大元素求和,Stream按相反顺序排序(sorted(comparator)
,其中比较器为reverseOrder()
),仅限于前3个元素(limit(3)
),这些元素是总结(sum()
首先将Stream<Integer>
转换为IntStream
Stream.mapToInt
}。
public static void main(String[] args) throws IOException {
Pattern pattern = Pattern.compile("(\\d+)");
try (Stream<String> stream = Files.lines(Paths.get("file"))) {
int sum =
stream.filter(line -> line.contains("PL"))
.map(pattern::matcher)
.filter(Matcher::find)
.map(m -> Integer.valueOf(m.group(1)))
.sorted(Comparator.reverseOrder())
.limit(3)
.mapToInt(Integer::intValue)
.sum();
System.out.println(sum);
}
}
对于您问题中的示例,输出为146999。
如果您确定文件中的"PL"
标识符将在要提取的数字之前,您甚至可以删除第一个过滤操作并使用模式".*PL.*?(\\d+)"
:此模式将匹配行包含"PL"
并捕获相应的数字。