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

1

Вот пример входных данных и ожидаемого результата. Я хочу выполнить эту операцию с единственной итерацией в списке ввода.

// input
Predicate<File> sizeP = f -> f.length() > 1_000_000; // size filter
Predicate<File> nameP = f -> f.getName().startsWith("Plot"); // name filter
List<File> fileList;
// output
// files list which satisfy the filter criteria
Map<Predicate<File>,List<File>> rulesToFiles = new HashMap<>();

// Example data
//  1. PlotPresentation.pptx-> 2 MB size      
//  2. Gen.docx-> 500 KB size
//  3. Group.docx-> 1.5 MB size
//  4. PlotDetails.docx-> 850 KB size
//  5. PlotDiagram.docx-> 5 MB size

// my map should have
Map<Predicate<File>,List<File>> rulesToFiles = new HashMap<>();
// [size-predicate]-> [PlotPresentation.pptx,Group.docx,PlotDiagram.docx]
// [name-predicate]-> [PlotPresentation.pptx,PlotDetails.docx,PlotDiagram.docx]
  • 0
    Что если элемент удовлетворяет обоим предикатам?
  • 0
    Этот вопрос будет легче читать, если вы включите больше описания в начале. Да, мы можем покопаться в вашем коде, чтобы попытаться выяснить вашу цель, но почему бы не объяснить это нам с самого начала?
Показать ещё 8 комментариев
Теги:
java-8
lambda

1 ответ

2

Чтобы связать полезные ключи с предикатами, мы можем использовать Map:

Map<String, Predicate<File>> pred=new TreeMap<>();
pred.put("size", f -> f.length() > 1_000_000);
pred.put("name", f -> f.getName().startsWith("Plot"));

Затем мы можем обрабатывать их следующим образом:

Map<String,List<File>> rulesToFiles = 
    fileList.stream().collect(Collectors.groupingBy(f->
        pred.entrySet().stream().filter(e->e.getValue().test(f))
            .map(Map.Entry::getKey).collect(Collectors.joining("+"))
    ));

это приводит к

 => [Gen.docx]
size => [Group.docx]
name => [PlotDetails.docx]
name+size => [PlotPresentation.pptx, PlotDiagram.docx]

который точно не указан в вашем вопросе, но весьма полезен. Может быть, вы можете жить с этим.

Но если это вас не удовлетворяет, вы можете применить постобработку к Map:

if(rulesToFiles.getClass()!=HashMap.class)// ensure mutable Map
    rulesToFiles=new HashMap<>(rulesToFiles);

rulesToFiles.remove(""); // remove the none-matching items
List<File> nameAndSize = rulesToFiles.remove("name+size");// remove&check for common items
if(nameAndSize!=null) {// merge them
    BinaryOperator<List<File>> merger=(a,b)->
        Stream.concat(a.stream(), b.stream()).collect(Collectors.toList());
    rulesToFiles.merge("size", nameAndSize, merger);
    rulesToFiles.merge("name", nameAndSize, merger);
}

результат:

size => [Group.docx, PlotPresentation.pptx, PlotDiagram.docx]
name => [PlotDetails.docx, PlotPresentation.pptx, PlotDiagram.docx]

Обновить:

Я подумал об этом и попросил решение создать Map в соответствии с запросом, прямо с помощью операции Stream в первую очередь, поэтому дополнительная операция не требуется. На основе Map<String, Predicate<File>> pred первого решения используйте:

Map<String,List<File>> rulesToFiles = fileList.stream()
    .flatMap(f -> pred.entrySet().stream().filter(e->e.getValue().test(f))
        .map(e->new AbstractMap.SimpleEntry<>(e.getKey(), f)))
    .collect(Collectors.groupingBy(Map.Entry::getKey,
        Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

Результат:

size => [PlotPresentation.pptx, Group.docx, PlotDiagram.docx]
name => [PlotPresentation.pptx, PlotDetails.docx, PlotDiagram.docx]
  • 0
    Ваше обновление не компилируется для меня. Я пытаюсь найти исправление, но кажется, что компилятор неправильно определяет типы, с которыми вы работаете, что в итоге приводит к Type mismatch: cannot convert from Map<Object,List<Object>> to Map<String,List<File>> error.
  • 1
    @Duncan: звучит странно, когда я попробовал несколько jdks ( jdk1.8.0_05 , jdk1.8.0_20 , jdk1.8.0_40 ), все они безупречно компилировали его. Вы используете JDK компилятор? И нет ли import ? Сообщения об ошибках могут иногда отвлекать от реальной проблемы. Это может помочь вставить явные аргументы типа, пока не будет выявлена реальная проблема, а затем снова удалить аргументы типа…
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню