Подскажите как с помощью лямбда выражения обработать определенную часть строки в коллекции?

Рейтинг: 2Ответов: 1Опубликовано: 09.03.2023
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,
    "Joseph Smith", "Thomas Doyle", "Ronald Pratt", "Thomas Spencer", "King Lee",
    "Gregory Smith", "Leroy Zimmerman", "Lee Smith", "Michael Harrington", 
    "Lee Daniels","Eugene Williams", "Lee Terry", "Arnold Fowler", "Billy Harrison", 
    "Lee Bennett", "Lee Evans", "Ronald Diaz", "Leonard King", "Timothy Smith", 
    "George Lee", "King Mann", "Dean Wright"
);
    
list.stream()
    .filter(s -> s.contains("K") || s.contains("S"))
    .filter(s -> !s.startsWith("K")&&!s.startsWith("S"))
    .sorted().distinct()
    .collect(Collectors.toList());

Метод должен вернуть имена людей, чья фамилия начинается с K или S, в формате имя + первая буква фамилии, например "David Z.". Список должен быть отсортирован по алфавиту и состоять только из уникальных значений

Ответы

▲ 2Принят

Для данных, представленных в формате "{firstName} {lastName}" можно отфильтровать слова при помощи String::matches и регулярного выражения типа "\\w+ [KS]\\w+". Соответственно, к отфильтрованным слов достаточно будет применить String::substring:

List<String> list = Arrays.asList(
    "Joseph Smith", "Thomas Doyle", "Ronald Pratt", "Thomas Spencer", "King Lee",
    "Gregory Smith", "Leroy Zimmerman", "Lee Smith", "Michael Harrington", "Lee Daniels","Eugene Williams", 
    "Lee Terry", "Arnold Fowler", "Billy Harrison", "Lee Bennett", "Lee Evans", "Ronald Diaz", 
    "Leonard King", "Timothy Smith", "George Lee", "King Mann", "Dean Wright"
);

List<String> fixed = list.stream()
    .filter(s -> s.matches("\\w+ [KS]\\w+"))
    .map(s -> s.substring(0, s.indexOf(" ") + 2) + ".")
    .sorted()
    .distinct()
    .collect(Collectors.toList());    

System.out.println(fixed); 
// -> [Gregory S., Joseph S., Lee S., Leonard K., Thomas S., Timothy S.]

Если имена состоят из трех и больше частей, но фамилией является последняя часть, регулярное выражение ".+ [KS]\\w+" и поиск фамилии следует исправить (искать последний пробел при помощи String::lastIndexOf):

List<String> list = Arrays.asList(
    "Joseph Smith", "Thomas Doyle", "Ronald Pratt Kimberly", "Thomas Spencer", "King Lee Roy Stapleton",
    "Gregory Smith", "Leroy Zimmerman", "Lee Smith Jacob", "Michael Harrington", "Lee Daniels","Eugene Williams", 
    "Lee Terry", "Arnold Fowler", "Billy Harrison", "Lee Bennett", "Lee Evans", "Ronald Diaz", 
    "Leonard King", "Timothy Smith", "George Lee", "King Mann", "Dean Wright"
);

List<String> fixed = list.stream()
    .filter(s -> s.matches(".+ [KS]\\w+"))
    .map(s -> s.substring(0, s.lastIndexOf(" ") + 2) + ".")
    .sorted()
    .distinct()
    .collect(Collectors.toList());    

System.out.println(fixed);
// -> [Gregory S., Joseph S., King Lee Roy S., Leonard K., Ronald Pratt K., Thomas S., Timothy S.]

Ещё один вариант: вместо String.substring применить String::replaceAll для замены части фамилии на точку -- выглядит более "красиво":

List<String> fixed = list.stream()
    .filter(s -> s.matches("(.+ [KS])(.*$)"))
    .map(s -> s.replaceAll("(.+ [KS])(.*$)", "$1."))
    .sorted()
    .distinct()
    .collect(Collectors.toList());