Java Поток Создать карту из списка объектов - PullRequest
2 голосов
/ 20 марта 2020

У меня есть такой класс.

public class Foo {
    private String prefix;
    private String sector;
    private int count;
}

Учитывая список foo:

//Args: prefix, sector, count
fooList.add(new Foo("44",,"RowC", 1 ));
fooList.add(new Foo("1",,"Rowa", 1 ));
fooList.add(new Foo("1",,"RowB", 1 ));
fooList.add(new Foo("1",,"Rowa", 1 ));

И мне нужно вернуть запрос на объект , отсортированный по префиксу как c вот так:

{
  "1": {
    "Rowa": "2",
    "RowB": "1"
  },
  "44": {
    "RowC": "1"
  }
}

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

fooList.stream()
       .collect(Collectors.groupingBy(
                Foo::getPrefix,
                Collectors.groupingBy(
                        Foo::getSector,
                        Collectors.mapping(Foo::getSector , Collectors.counting())
                )
        ));

Проблема в том, что приведенный выше код состоит в том, что счетчик является длинным, и мне нужно возвращаться как строка. Я пытался с .toString, но он дает мне ошибку (может присвоить java .lang.String для java .util.stream.Collector).

ОБНОВЛЕНИЕ

С помощью Андреаса и Намана теперь я могу отобразить счет как строку. Мне просто нужно отсортировать по префиксу.

Кто-нибудь может мне помочь?

Ответы [ 2 ]

2 голосов
/ 20 марта 2020

Вы были почти там, просто замените строку Collectors.mapping на:

Collectors.summingInt(Foo::getCount))

Как в:

List<Foo> fooList = new ArrayList<>();
fooList.add(new Foo("44", "RowC", 1 ));
fooList.add(new Foo("1", "Rowa", 1 ));
fooList.add(new Foo("1", "RowB", 1 ));
fooList.add(new Foo("1", "Rowa", 1 ));

Map<String, Map<String, String>> result = fooList.stream().collect(
        Collectors.groupingBy(
                Foo::getPrefix,
                TreeMap::new, // remove if prefix sorting not needed
                Collectors.groupingBy(
                        Foo::getSector,
                        () -> new TreeMap<>(Collator.getInstance()), // remove if sector sorting not needed
                        Collectors.collectingAndThen(
                                Collectors.summingInt(Foo::getCount),
                                String::valueOf
                        )
                )
        )
);

System.out.println(result); // prints: {1={Rowa=2, RowB=1}, 44={RowC=1}}

Обратите внимание на конструкторы TreeMap, добавленные к groupingBy() звонки, что гарантирует, что карты отсортированы. Первая сортировка лексикографически , а вторая сортировка в соответствии с разговорным языком, то есть прописные и строчные буквы не влияют на порядок.

0 голосов
/ 23 марта 2020

Это то, что вам нужно?

Код:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;

public class Main {
    public static void main(String [] args){
        List<Foo> fooList = new ArrayList<>();
        fooList.add(new Foo("44", "RowC", 1 ));
        fooList.add(new Foo("1", "Rowa", 1 ));
        fooList.add(new Foo("1", "RowB", 1 ));
        fooList.add(new Foo("1", "Rowa", 1 ));

        Map<String, Map<String, Integer>> result = grouper(fooList);
        result.forEach( (k,v) -> System.out.printf("%s\n%s\n", k,v) );
    }

    /* group the list by the prefix, and then show, every sector and the
    *  count(*) of items on the list with the same row and sector.*/
    public static Map<String, Map<String, Integer>> grouper(List<Foo> foos){
        //Map<prefix, Map<sector, count>
        Map<String, Map<String, Integer>> result = foos.stream()
                .collect(
                        //Step 1 - group by prefix. Outer map key is prefix.
                        groupingBy( Foo::getPrefix,
                                //Use a tree map which wil be sorted by its key, i.e prefix.
                                TreeMap::new,
                                //Step 2 - group by sector.
                                groupingBy( Foo::getSector,
                                        //Step 3 - Sum the Foo's in each sector in each prefix.
                                        summingInt(Foo::getCount)
                                )
                        )
                );
        return result;
    }

}

Выход:

1
{Rowa=2, RowB=1}
44
{RowC=1}

PS - я упоминал на этот урок чтобы ответить на ваш вопрос. Я ссылался на примеры в « 2.5. Группирование по нескольким полям » и « 2.7. Получение суммы из сгруппированных результатов ». Следующим шагом было выяснить, как также упорядочить по ключу карты во время группировки, которую я получил из « 2.11. Изменение типа возвращаемой карты », а также проверил ее здесь .

...