【问题标题】:How do you use java stream api to convert list of objects into a nested map based on information stored inside object?你如何使用java stream api根据对象内部存储的信息将对象列表转换为嵌套映射?
【发布时间】:2020-05-25 15:18:02
【问题描述】:

我有一个对象列表List<SingleDay>,其中SingleDay

class SingleDay{ 
      private Date date;
      private String County;

   // otherstuff
}

我希望将此列表转换为Map<Date, Map<String, SingleDay>>。也就是说,我想要一张从 Date 到 Counties 的地图,再回到原始对象。

例如:
02/12/2020 : { "Rockbridge": {SingleDayObject}}

如果从对象列表到地图,而不是从对象列表到嵌套地图,我无法得到任何工作以及我在网上找到的所有内容。

基本上,我希望能够快速查询到对应日期和县的对象。

谢谢!

【问题讨论】:

  • 您可以认为您将数据存储在 Map 中,其中字符串可以是 'date:country',值是 singleDay 对象
  • 是否有可能有 SingleDay 对象与重复的 datecountry
  • @Deadpool 不,但我想知道如果它意外发生如何处理。我是从 csv 读取的,所以我想是有可能的

标签: java date java-stream


【解决方案1】:

按如下方式进行:

Map<LocalDate, Map<String, SingleDay>> result = list.stream()
                .collect(Collectors.toMap(SingleDay::getDate, v -> Map.of(v.getCounty(), v)));

演示:

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class SingleDay {
    private LocalDate date;
    private String County;

    public SingleDay(LocalDate date, String county) {
        this.date = date;
        County = county;
    }

    public LocalDate getDate() {
        return date;
    }

    public String getCounty() {
        return County;
    }

    @Override
    public String toString() {
        return "SingleDay [date=" + date + ", County=" + County + "]";
    }
    // otherstuff
}

public class Main {
    public static void main(String[] args) {
        List<SingleDay> list = List.of(new SingleDay(LocalDate.now(), "X"),
                new SingleDay(LocalDate.now().plusDays(1), "Y"), new SingleDay(LocalDate.now().plusDays(2), "Z"));

        Map<LocalDate, Map<String, SingleDay>> result = list.stream()
                .collect(Collectors.toMap(SingleDay::getDate, v -> Map.of(v.getCounty(), v)));

        // Display
        result.forEach((k, v) -> System.out.println("Key: " + k + ", Value: " + v));
    }
}

输出:

Key: 2020-05-27, Value: {Z=SingleDay [date=2020-05-27, County=Z]}
Key: 2020-05-26, Value: {Y=SingleDay [date=2020-05-26, County=Y]}
Key: 2020-05-25, Value: {X=SingleDay [date=2020-05-25, County=X]}

注意:我使用的是LocalDate,而不是过时的java.util.Date。我强烈建议您使用java.time API 而不是损坏的java.util.Date。查看this 了解更多信息。

【讨论】:

  • 不错的答案+1。我确实收到以下警告Type mismatch: cannot convert from Map&lt;Date,Object&gt; to Map&lt;Date,Map&lt;String,SingleDay&gt;&gt;
  • 关于使用 LocalDate 而不是 Date 的好建议,尽管我不太确定您的整体解决方案。预期的结果不应该类似于list.stream().collect(Collectors.toMap(SingleDay::getDate, v -&gt; Map.of(v.getCounty(), v))); 吗?还是我错过了 OP 标准中的某些内容?使用您当前的方法,每个外部地图映射都将具有与内部地图相同的值。
  • 谢谢,@OusmaneD。为反馈。我在写解决方案时不确定,但在发表您的评论后,我认为这是有道理的。我已经采纳了你的建议。如果他期待这个或原始解决方案,我会等待 OP 的评论。
  • @Code_Mode 实际上问题最初并没有用 java-8 标记。因此我建议Map.of
  • 最初的答案是将整个列表收集到 Map 中,而不是 date 键,而更新后的答案(感谢 @OusmaneD. 的及时建议)是将条目的值与键。
【解决方案2】:

一个更易读的数据结构是Map&lt;SingleDay, SingleDay&gt;。可能看起来是多余的,但可以让您轻松找到您的对象。

Map<SingleDay, SingleDay> myMap = new HashMap();
list.forEach(day -> myMap.put(day, day));

然后你就可以得到一个

SingleDay day = mMap.get(myDay);

非常重要的是不要忘记根据您认为相等的内容覆盖SingleDayequals() 方法。

【讨论】:

  • 但是,给定一个日期,我将无法找到相应的 SingleDays。我已经需要它了,对吧
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 2011-11-22
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
相关资源
最近更新 更多