[英]Any way to make this stream more efficient?
How would one optimise this without adding value into the new ArrayList instead just having the original list updated?如果不向新的 ArrayList 增加价值,而只是更新原始列表,如何优化这一点?
String filterval = filter.toLowerCase();
ArrayList<String> filtredArr = new ArrayList<String>();
listArray.forEach(
valueText -> {
String val = valueText.toLowerCase();
if (val.startsWith(filterval) || val.contains(filterval))
filtredArr.add(valueText);
else {
Arrays.stream(valueText.split(" ")).forEach(
singleWord -> {
String word = singleWord.toLowerCase();
if(word.startsWith(filterval) || word.contains(filterval))
filtredArr.add(valueText);
}
);
}
});
When using streams, it is best not to modify the source of the stream while the latter iterates over the former.使用流时,最好不要修改 stream 的源,而后者会迭代前者。 (See this for instance.)
(例如看这个。)
Regarding readability and making idiomatic use of stream operations, your code is almost indistinguishable from a plain old for loop (and I would advise you to change it to that if you only use streams to do a forEach
, but you could modify it to use a chain of shorter and more "atomic" stream operations, as in the following examples.关于可读性和惯用 stream 操作,您的代码与普通的旧 for 循环几乎没有区别(如果您只使用流来执行
forEach
,我建议您将其更改为,但您可以修改它以使用更短且更“原子”的 stream 操作链,如下例所示。
To get the list of strings in which at least one word contains filterval
:要获取至少一个单词包含
filterval
的字符串列表:
List<String> filtered = listArray.stream().filter(str -> str.toLowerCase().contains(filterval)).collect(Collectors.toList());
To get the list of strings in which at least one word starts with filterval
:要获取至少一个单词以
filterval
开头的字符串列表:
List<String> filtered = listArray.stream().filter(str -> Arrays.stream(str.split(" ")).map(String::toLowerCase).anyMatch(word -> word.startsWith(filterval))).collect(Collectors.toList());
To get the list of words (in any of the strings) that contain the filter value:要获取包含过滤器值的单词列表(在任何字符串中):
List<String> filteredWords = listArray.stream().map(String::toLowerCase).flatMap(str -> Arrays.stream(str.split(" "))).filter(word -> word.contains(filterval)).collect(Collectors.toList());
(I'm assuming listArray
, which you don't show in your code snippet, is a List<String>
.) (我假设您未在代码片段中显示的
listArray
是List<String>
。)
val.startsWith(filterval) || val.contains(filterval)
val.startsWith(filterval) || val.contains(filterval)
val.startsWith(filterval) || val.contains(filterval)
is completely equivalent to val.contains(filterval)
. val.startsWith(filterval) || val.contains(filterval)
完全等同于val.contains(filterval)
。 The reason is, if a string starts with filterval
, it must also mean that it contains it;filterval
,它也一定意味着它包含它; one implies the other.split
to all of them and then "concatenate" the sequences of words by using filterMap
.split
应用于所有它们,然后使用filterMap
将单词序列“连接”起来。import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
String filterval = "ba";
List<String> listArray = List.of("foo", "BAR", "spam EGGS ham bAt", "xxbazz");
List<String> filtered1 = listArray.stream()
.filter(str -> str.toLowerCase().contains(filterval))
.collect(Collectors.toList());
List<String> filtered2 =
listArray.stream()
.filter(str -> Arrays.stream(str.split(" "))
.map(String::toLowerCase)
.anyMatch(word -> word.startsWith(filterval)))
.collect(Collectors.toList());
List<String> filtered3 = listArray.stream()
.map(String::toLowerCase)
.flatMap(str -> Arrays.stream(str.split(" ")))
.filter(word -> word.contains(filterval))
.collect(Collectors.toList());
System.out.println(Arrays.toString(filtered1.toArray()));
System.out.println(Arrays.toString(filtered2.toArray()));
System.out.println(Arrays.toString(filtered3.toArray()));
}
}
Output: Output:
[BAR, spam EGGS ham bAt, xxbazz]
[BAR, spam EGGS ham bAt]
[bar, bat, xxbazz]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.