简体   繁体   English

有什么方法可以让这个 stream 更高效?

[英]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> .) (我假设您未在代码片段中显示的listArrayList<String> 。)

Notes笔记

  • The condition 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.一个暗示另一个。
  • There's no need to compute the lowercase versions of single words since you've already lowercased the whole string (so any words within it will also be lowercase).无需计算单个单词的小写版本,因为您已经将整个字符串小写(因此其中的任何单词也将是小写的)。
  • Instead of treating single words and space-separated strings separately, we can apply split to all of them and then "concatenate" the sequences of words by using filterMap .除了单独处理单个单词和空格分隔的字符串,我们可以将split应用于所有它们,然后使用filterMap将单词序列“连接”起来。

Minimal, complete, verifiable example最小的、完整的、可验证的例子

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM