简体   繁体   English

使用Java 8流过滤包含来自另一个列表中的一个或多个字符串的字符串列表

[英]Filter a list of strings which contains one or more strings from another list with Java 8 streams

I want to use the strings imputed in a TextField to filter a list. 我想使用TextField中插入的字符串来过滤列表。 I am using a KeyReleased Event on the TextField to filter the list on every key. 我在TextField上使用KeyReleased事件来过滤每个键上的列表。 The piece of code below filters the list when I type in a word, but when I press space and start typing another word the list gets empty. 当我输入单词时,下面的代码片段会过滤列表,但是当我按空格键并开始键入另一个单词时,列表会变空。 I am a bit new to streams. 我对溪流有点新意。 I don't know what I am doing wrong. 我不知道我做错了什么。


private ObservableList<Products_Data> productList;
@FXML       
private JFXTextField searchField;
@FXML       
private TableView<Products_Data> productTable;
@FXML
void searchKeyReleased(KeyEvent event) {
    String searchText = searchField.getText();
    List<String> searchableWords = Arrays.asList(searchText.toLowerCase().trim().split("\\s+"));
    List<Products_Data> filteredList =  searchableWords.stream()
        .flatMap(i ->productList.stream()
        .filter(j -> j.getPartDesc().toLowerCase().contains(i)))
        .collect(Collectors.toList());
    ObservableList<Products_Data> productFilteredList = FXCollections.observableArrayList(filteredList);
    productTable.setItems(productFilteredList);
}

----------
public class Products_Data {
    private final StringProperty partDesc = new (this,"PartDesc",null);

    public Products_Data() {}

    public final StringProperty getPartDescProperty() {return partDesc;}
    public final String getPartDesc(){return partDesc.get();}
    public final void setPartDesc(String partDesc) {     
        getPartDescProperty().set(partDesc);
    }

}

I can't see a fundamental problem in your Stream code. 我无法在您的Stream代码中看到根本问题。 The way, you've written it, is not very efficient and it allows elements matching multiple words to occur multiple times in the result list. 你编写它的方式不是很有效,它允许在结果列表中多次出现匹配多个单词的元素。 Perhaps, the UI you're setting the result on can't handle this. 也许,您设置结果的UI无法处理此问题。

I'd create a single filter out of the entered text, which will match if any of the words appears in the element, using a case insensitive matching instead of repeatedly converting every string to lowercase. 我将从输入的文本中创建一个单独的过滤器,如果元素中出现任何单词,它将匹配,使用不区分大小写的匹配,而不是重复地将每个字符串转换为小写。 Eg with a utility method like this: 例如,使用这样的实用方法:

static final Pattern SPACE = Pattern.compile("\\s+");

public static <T> Predicate<T> getFilter(Function<? super T, String> f, String words) {
    String regex = SPACE.splitAsStream(words)
        .map(Pattern::quote).collect(Collectors.joining("|"));
    Predicate<String> sp = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).asPredicate();
    return t -> sp.test(f.apply(t));
}

which can be used as 可以用作

List<Products_Data> filteredList = productList.stream()
    .filter(getFilter(Products_Data::getPartDesc, searchField.getText()))
    .collect(Collectors.toList());

The core of your matching should be like this: 匹配的核心应该是这样的:

productList.stream().filter(
    product -> searchableWords.stream().allMatch(
        searchWord -> product.getPartDesc().toLowerCase().contains(searchWord)
    )
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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