Возможно ли с помощью Java 8 создать список или любую другую структуру данных, сгруппированную, упорядоченную и подсчитанную за один шаг? - PullRequest
0 голосов
/ 23 июня 2019

У меня есть файл с такой структурой:

a, City1, 2013-09-05 14:08:15
b, City2, 2015-10-08 16:10:15
c, City2, 2010-09-05 14:08:15
d, City1, 2011-09-05 14:08:15

Это значения, разделенные запятыми, и строки, разделенные символом конца строки.

Мне нужно создать структуру данных в Java 8, где у меня есть строки, сгруппированные по городам и внутри каждой такой группы, отсортированные по дате в порядке возрастания и подсчета количества строк в каждой группе.

Я пытался:

  1. Создать List<Row> из файла
  2. Создайте Map<String, List<Row>>, который сгруппирован по городам и отсортирован по дате в каждой группе
  3. Создать Map<String, Long> для группировки по городу и количеству строк

Это код, который я пробовал:

public PhotoResponse processFile()  {
    //read each line of the file and create a new object PhotoIn for each one
    List<PhotoIn> lista = null;
    try {
        lista = Files.lines(Paths.get(file))
        .map(line -> line.split(","))
        .map(photo -> new PhotoIn(photo[0].substring(0, photo[0].lastIndexOf(".")), photo[0].substring(photo[0].lastIndexOf(".") + 1 ), photo[1].trim(), parseDate(photo[2]), index++))
        .collect(Collectors.toList());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return generateOutput(lista); 
}


private PhotoResponse generateOutput(List<PhotoIn> photos) {

    //Grouping photos by city
    Map<String, List<PhotoIn>> photosByCity = photos.stream().collect(Collectors.groupingBy(PhotoIn::getCity));

    //Sorting photos by date into each city
    photosByCity.values().forEach(list -> list.sort(Comparator.comparing(PhotoIn::getDate)));

    //Grouping photos by city and amount
    Map<String, Long> numeroPorCiudades = photos.stream().collect(Collectors.groupingBy(PhotoIn::getCity, Collectors.counting()));

    List<PhotoOut> photoOutList = new ArrayList<PhotoOut>();

    photosByCity.forEach((key, list) -> {
        String digits = Integer.toString(Long.toString(numeroPorCiudades.get(key)).length());
        counter = 1;
        list.forEach(photoIn -> {
            photoOutList.add(new PhotoOut(photoIn.getName() + "." + photoIn.getExtension(), key + String.format("%0" + digits + "d", counter++) + "." + photoIn.getExtension(), photoIn.getIndex()));
        });
    });
    return sortOutput(photoOutList);
}

Я решаю проблему, но ищу лучший и более эффективный способ сделать это с помощью Java 8. Можно ли выполнить эти 3 шага всего за один шаг? . Мне нужно сгруппировать всю эту информацию в одну структуру данных.

Ответы [ 2 ]

2 голосов
/ 23 июня 2019

С этой моделью:

class Model {
  private String title;
  private String city;
  private LocalDateTime date;
}

Это можно сделать так:

List<Model> list = getFromFile();

Comparator<Model> comparator = Comparator.comparing(Model::getDate);

//grouping the list by City with lists sorted by date
Map<String, List<Model>> map = list.stream()
    .collect(
        Collectors.groupingBy( //grouping the list by City with lists 
            m -> m.getCity(),
            Collectors.collectingAndThen(Collectors.toList(), l->{
              l.sort(comparator);
              return l;
            })
        )
    );

//getting another map with counts
Map<String, Object> countMap = map.entrySet().stream()
    .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().size()));
0 голосов
/ 23 июня 2019

Предполагается, что класс Row с ожидаемым конструктором и получателями для простоты опущен:

public class Row {
    String photo;
    String city;
    int date;
}

и:

List<Row> data = new ArrayList<>(); /* fill the list */

Свести таблицы по городам относительно просто:

Map<String, Long> counts = data.stream()
    .collect(Collectors.groupingBy(Row::getCity, Collectors.counting()));

Группировать по городам и сортировать по дате немного сложнее. Как указано в комментариях, этого можно достичь, сгруппировав строки и собрав их в TreeSet, структуру данных, которая сохраняет свои элементы (в данном случае Row) упорядоченными.

Следующий код использует временные переменные для начальной ясности, но они могут быть встроены в окончательное решение:

// Defines a factory that creates a TreeSet for rows where rows are ordered by date
Supplier<TreeSet<Row>> treeSetSupplier = () -> new TreeSet<Row>(Comparator.comparing(Row::getDate));

// Create a collector that accumulates rows into this TreeSet
Collector<Row, ?, TreeSet<Row>> collector = Collectors.toCollection(treeSetSupplier);

// Group by city, accumulating results into the defined TreeSet
Map<String, TreeSet<Row>> result = data.stream()
        .collect(Collectors.groupingBy(Row::getCity, collector));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...