如何从流中收集地图的地图

huangapple go评论72阅读模式
英文:

How to collect a map of maps from stream

问题

我已经创建了以下类

public class Data {
    
    String name;
    String dateOfBirth;
    String dateAttendedClass;

}

我有一个Data的列表,并想要创建以下的映射:

Map<String, Map<String, List<String>>>

Map<dateOfBirth, Map<name, list(dateAttendedClass)>>

通过以下方式,我成功创建了以下的映射:

Map<String, List<String>> nameAttendedClassMap = data.stream()
            .collect(Collectors.groupingBy(Data::getName,
                    Collectors.mapping(Data::getDateAttendedClass, Collectors.toList())));

但是,我不确定如何进一步收集此映射并将其放入一个以出生日期为键的映射中:

Map<String, Map<String, List<String>>>
英文:

I have below class

public class Data {
	
	String name;
	String dateOfBirth;
	String dateAttendedClass;

}

I have a list of Data and wanted to create a map of below:

Map&lt;String Map&lt;String, List&lt;String&gt;&gt;&gt;

Map&lt;dateOfBirth Map&lt;name,list(dateAttendedClass)&gt;&gt;

I managed to create a Map of

Map&lt;name,list(dateAttendedClass)&gt;

by doing this

	Map&lt;String, List&lt;String&gt;&gt; nameAttendedClassMap = data.stream()
			.collect(Collectors.groupingBy(Data::getName,
					Collectors.mapping(Data::getDateAttended, Collectors.toList())));

But I am not sure how to collect this map further and have it in a map with the key being date of birth.

Map&lt;String Map&lt;String, List&lt;String&gt;&gt;&gt;

答案1

得分: 3

你需要像这样使用 Collectors.mapping

Map<String, Map<String, List<String>>> nameAttendedClassMap = data.stream()
        .collect(groupingBy(Data::getDateOfBirth,
                 groupingBy(Data::getName, 
                       mapping(Data::getDateAttendedClass, Collectors.toList())));

你需要使用 Collectors.groupingBy 根据 dateOfBirth 对 Data 对象进行分组,然后再次根据 name 对 Data 对象进行分组,最后使用 Collectors.mapping 将每个 Data 对象的 dateAttendedClass 字段映射到一个列表中。

英文:

You need Collectors.mapping like this:

Map&lt;String, Map&lt;String, List&lt;String&gt;&gt;&gt; nameAttendedClassMap = data.stream()
        .collect(groupingBy(Data::getDateOfBirth,
                 groupingBy(Data::getName, 
                       mapping(Data::getDateAttendedClass, Collectors.toList()))));

You need to group the Data objects by dateOfBirth using Collectors.groupingBy, then group the Data objects again by name and finally map the dateAttendedClass field of each Data object to a list using Collectors.mapping.

答案2

得分: 2

根据他人建议,您应该嵌套您的groupingBy调用。

这是一个可用的示例。您应该将日期存储为时代值。这是存储值的最佳方式。以这种方式存储它们更具可传输性和通用性。如果要显示任何信息,您可以调用方便的方法来格式化。当日期表示为整数时,您可以指定要用于格式化日期的区域设置。在排序时或一般比较时,也没有必要解析日期。

此外,给您的对象命名合适的名称。将Data的名称更改为Student有助于确定对象代表什么。

package org.example;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import com.google.gson.GsonBuilder; // 用于打印格式化的JSON

public class DataMap {
    private static final DateTimeFormatter dateFormatter;
    private static final DateTimeFormatter yearFormatter;

    static {
        dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        yearFormatter = DateTimeFormatter.ofPattern("yyyy");
    }

    public static void main(String[] args) {
        List<Student> data = new ArrayList<Student>();
        data.add(createStudent("Billy", "1990-01-30", "2005-08-28"));
        data.add(createStudent("Billy", "1990-01-30", "2006-08-28"));
        data add(createStudent("Billy", "1990-01-31", "2007-08-28"));
        data.add(createStudent("Billy", "1990-01-31", "2008-08-28"));
        data.add(createStudent("Alice", "1990-01-30", "2005-08-28"));
        data.add(createStudent("Alice", "1990-01-30", "2006-08-28"));
        data.add(createStudent("Alice", "1990-01-31", "2007-08-28"));
        data.add(createStudent("Alice", "1990-01-31", "2008-08-28"));

        Map<String, Map<String, List<String>>> grouped = groupAttendanceByBirthAndName(data);
        System.out.println(grouped);

        // 供显示用...
        System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(grouped).toString());
    }

    private static Map<String, Map<String, List<String>>> groupAttendanceByBirthAndName(List<Student> students) {
        return students.stream()
                .collect(Collectors.groupingBy(Student::getDateOfBirthAsString,
                        Collectors.groupingBy(Student::getName,
                                Collectors.mapping(Student::getDateAttendedClassAsString, Collectors.toList()))));
    }

    private static String formatEpochMilliAsDate(long epochMilli, DateTimeFormatter dateFormatter) {
        return dateFormatter.format(Instant.ofEpochMilli(epochMilli).atZone(ZoneId.systemDefault()).toLocalDate());
    }

    private static long epochFromDate(String date) {
        return LocalDate.parse(date).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    private static Student createStudent(String name, String birthYear, String attendanceYear) {
        return new Student(name, epochFromDate(birthYear), epochFromDate(attendanceYear));
    }

    private static class Student {
        private String name;
        private long dateOfBirth;
        private long dateAttendedClass;

        public Student(String name, long dateOfBirth, long dateAttendedClass) {
            this.name = name;
            this.dateOfBirth = dateOfBirth;
            this.dateAttendedClass = dateAttendedClass;
        }

        public String getName() {
            return name;
        }

        public long getDateOfBirth() {
            return dateOfBirth;
        }

        // 方便方法 ~ 用于分组和显示
        public String getDateOfBirthAsString() {
            return formatEpochMilliAsDate(dateOfBirth, dateFormatter);
        }

        public long getDateAttendedClass() {
            return dateAttendedClass;
        }

        // 方便方法 ~ 用于分组和显示
        public String getDateAttendedClassAsString() {
            return formatEpochMilliAsDate(dateAttendedClass, yearFormatter);
        }
    }
}

输出

原始Map输出:

{1990-01-31={Billy=[2007, 2008], Alice=[2007, 2008]}, 1990-01-30={Billy=[2005, 2006], Alice=[2005, 2006]}}

我使用了Google的Gson库来将嵌套的地图漂亮地打印为JSON。您也可以使用Jackson的ObjectMapper

英文:

As suggested by others, you should nest your groupingBy calls.

Here is a working example. You should store your dates as epoch values. This is the best way to store the values. They are more transportable and universal this way. If you want to display any information, you can call convenience methods to format. When a date is represented as an integer, you can specify what locale you want to use to format the date. There is also no need to pare the dates when comparing them when sorting; or comparing in general.

Also, name your objects appropriately. Changing the name of Data to Student helps identify what the object represents.

package org.example;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import com.google.gson.GsonBuilder; // Used for printing formatted JSON

public class DataMap {
    private static final DateTimeFormatter dateFormatter;
    private static final DateTimeFormatter yearFormatter;

    static {
        dateFormatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;);
        yearFormatter = DateTimeFormatter.ofPattern(&quot;yyyy&quot;);
    }

    public static void main(String[] args) {
        List&lt;Student&gt; data = new ArrayList&lt;Student&gt;();
        data.add(createStudent(&quot;Billy&quot;, &quot;1990-01-30&quot;, &quot;2005-08-28&quot;));
        data.add(createStudent(&quot;Billy&quot;, &quot;1990-01-30&quot;, &quot;2006-08-28&quot;));
        data.add(createStudent(&quot;Billy&quot;, &quot;1990-01-31&quot;, &quot;2007-08-28&quot;));
        data.add(createStudent(&quot;Billy&quot;, &quot;1990-01-31&quot;, &quot;2008-08-28&quot;));
        data.add(createStudent(&quot;Alice&quot;, &quot;1990-01-30&quot;, &quot;2005-08-28&quot;));
        data.add(createStudent(&quot;Alice&quot;, &quot;1990-01-30&quot;, &quot;2006-08-28&quot;));
        data.add(createStudent(&quot;Alice&quot;, &quot;1990-01-31&quot;, &quot;2007-08-28&quot;));
        data.add(createStudent(&quot;Alice&quot;, &quot;1990-01-31&quot;, &quot;2008-08-28&quot;));

        Map&lt;String, Map&lt;String, List&lt;String&gt;&gt;&gt; grouped = groupAttendanceByBirthAndName(data);
        System.out.println(grouped);

        // For display purposes...
        System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(grouped).toString());
    }

    private static Map&lt;String, Map&lt;String, List&lt;String&gt;&gt;&gt; groupAttendanceByBirthAndName(List&lt;Student&gt; students) {
        return students.stream()
                .collect(Collectors.groupingBy(Student::getDateOfBirthAsString,
                        Collectors.groupingBy(Student::getName,
                                Collectors.mapping(Student::getDateAttendedClassAsString, Collectors.toList()))));
    }

    private static String formatEpochMilliAsDate(long epochMilli, DateTimeFormatter dateFormatter) {
        return dateFormatter.format(Instant.ofEpochMilli(epochMilli).atZone(ZoneId.systemDefault()).toLocalDate());
    }

    private static long epochFromDate(String date) {
        return LocalDate.parse(date).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    private static Student createStudent(String name, String birthYear, String attendanceYear) {
        return new Student(name, epochFromDate(birthYear), epochFromDate(attendanceYear));
    }

    private static class Student {
        private String name;
        private long dateOfBirth;
        private long dateAttendedClass;

        public Student(String name, long dateOfBirth, long dateAttendedClass) {
            this.name = name;
            this.dateOfBirth = dateOfBirth;
            this.dateAttendedClass = dateAttendedClass;
        }

        public String getName() {
            return name;
        }

        public long getDateOfBirth() {
            return dateOfBirth;
        }

        // Convenience method ~ Used for grouping and display
        public String getDateOfBirthAsString() {
            return formatEpochMilliAsDate(dateOfBirth, dateFormatter);
        }

        public long getDateAttendedClass() {
            return dateAttendedClass;
        }

        // Convenience method ~ Used for grouping and display
        public String getDateAttendedClassAsString() {
            return formatEpochMilliAsDate(dateAttendedClass, yearFormatter);
        }
    }
}

Output

Raw Map output:

{1990-01-31={Billy=[2007, 2008], Alice=[2007, 2008]}, 1990-01-30={Billy=[2005, 2006], Alice=[2005, 2006]}}

I used Google's Gson library to pretty-print the nested map as JSON. You could use Jackson's ObjectMapper as well.

{
  &quot;1990-01-31&quot;: {
    &quot;Billy&quot;: [
      &quot;2007&quot;,
      &quot;2008&quot;
    ],
    &quot;Alice&quot;: [
      &quot;2007&quot;,
      &quot;2008&quot;
    ]
  },
  &quot;1990-01-30&quot;: {
    &quot;Billy&quot;: [
      &quot;2005&quot;,
      &quot;2006&quot;
    ],
    &quot;Alice&quot;: [
      &quot;2005&quot;,
      &quot;2006&quot;
    ]
  }
}

huangapple
  • 本文由 发表于 2023年3月7日 03:35:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75655095.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定