Java 8 удаление элемента из массива / списка массивов на основе регулярных выражений - PullRequest
0 голосов
/ 21 февраля 2019

Есть ли лучший способ добиться следующего в Java 8?

String regex = "^SACHI";
for (String temp : personalNames ) {
    if (temp.matches(regex)){
         personalNames.remove(temp);
    }
}

Ответы [ 6 ]

0 голосов
/ 21 февраля 2019
   String regex = "^SACHI";
   Predicate<String> f = n-> n.matches(regex);
   personalNames.stream().filter(x->f.test(x))
                         .forEach(n-> {
                          personalNames.remove(n);
                          });

Использование Predicate<T> для фильтрации имен, которые не соответствуют String regex.test(T t) оценивает этот предикат по заданному аргументу.

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

Вы можете использовать

personalNames.removeIf(Pattern.compile("^SACHI").asPredicate());

Вы также можете использовать более простой

personalNames.removeIf(s -> s.matches("^SACHI"));

, но он будет выполнять Pattern.compile("^SACHI") под капотом, для каждого элемента в худшем случае.Обратите внимание, что Pattern, созданный compile, является неизменным и может использоваться совместно, следовательно, вы также можете создать его только один раз, например

static final Pattern REMOVAL_PATTERN = Pattern.compile("^SACHI");

, и использовать его как

personalNames.removeIf(REMOVAL_PATTERN.asPredicate());

asPredicate() использует find() вместо matches(), но поскольку ваш паттерн имеет привязку ^, это не имеет значения.Метод asMatchPredicate() для получения предиката с использованием matches() был добавлен в JDK 11.


Если все, что вам нужно, это сопоставить буквенную строку в начале, вы также можете использовать

personalNames.removeIf(s -> s.startsWith("SACHI"));

, для которого не требуются затраты на инициализацию регулярного выражения.

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

Они эквивалентны:

for (String temp : personalNames ) {
   if (temp.matches(regex)){
     personalNames.remove(temp);
   }
}

и

personalNames.removeIf(name -> name.matches(regex));
0 голосов
/ 21 февраля 2019

Это зависит от того, нужно ли вам модифицировать существующий список, или вам просто нужно получить список без элементов.В первом случае вы можете использовать поток для фильтрации несоответствующих объектов и удаления их из списка

personalNames.removeAll(
        personalNames
                .stream()
                .filter(x -> !x.matches(regex))
                .collect(Collectors.toList())
);

В другом случае вы можете просто вернуть новый список только с соответствующими объектами

final List<String> matchingElements = personalNames.stream()
        .filter(x -> x.matches(regex))
        .collect(Collectors.toList());

также этот код

for (String temp : personalNames ) {
    if (temp.matches(regex)){
        personalNames.remove(temp);
    }
}

будет выбрасывать java.util.ConcurrentModificationException

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

Добавление и / или удаление элементов из существующего контейнера не вписывается в концепции функционального программирования.Более того, такое поведение не является потокобезопасным в параллельной и параллельной среде.Обеспечение безопасности потока также требует больших усилий.Поэтому предпочитайте лямбды без стеков лямбдам с сохранением состояния в качестве хорошей инженерной практики.Вы можете получить соответствующие имена, просто используя оператор фильтра.Вот как это выглядит.

private static final Pattern PATTERN = Pattern.compile("^SACHI");

List<String> validNames = personalNames.stream()
    .filter(PATTERN.asPredicate())
    .collect(Collectors.toList());
0 голосов
/ 21 февраля 2019

Вы можете извлечь errorProneNames с помощью filtering и удалить соответствующие имена ошибок из personalNames, повторяя forEach:

List<String> errorProneNames = personalNames.stream()
        .filter(name -> !name.matches(regex))
        .collect(Collectors.toList());

errorProneNames.forEach(personalNames::remove);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...