Фильтрация списка строк, который содержит одну или несколько строк из другого списка с потоками Java 8 - PullRequest
0 голосов
/ 15 февраля 2019

Я хочу использовать строки, вмененные в TextField, для фильтрации списка.Я использую KeyReleased Event в TextField для фильтрации списка по каждому ключу.Часть кода ниже фильтрует список, когда я набираю слово, но когда я нажимаю пробел и начинаю набирать другое слово, список становится пустым.Я немного новичок в потоках.Я не знаю, что я делаю не так.


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);
    }

}

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Я не вижу фундаментальной проблемы в вашем коде Stream.Способ, который вы написали, не очень эффективен и позволяет элементам, совпадающим с несколькими словами, встречаться в списке результатов несколько раз.Возможно, пользовательский интерфейс, для которого вы устанавливаете результат, не может это обработать.

Я бы создал один фильтр из введенного текста, который будет соответствовать, если в элементе появится какое-либо слово, используясопоставление без учета регистра вместо многократного преобразования каждой строки в нижний регистр.Например, с помощью такого вспомогательного метода:

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));
}

, который можно использовать как

List<Products_Data> filteredList = productList.stream()
    .filter(getFilter(Products_Data::getPartDesc, searchField.getText()))
    .collect(Collectors.toList());
0 голосов
/ 15 февраля 2019

Ядро вашего соответствия должно быть таким:

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