繁体   English   中英

如何从地图获取每周最大值<LocalDate,Integer>使用流

[英]How to get weekly max value from Map<LocalDate,Integer> using streams

问题:

  • 我有一个Map<LocalDate, Integer>并且我想使用LocalDate按周对这些地图元素进行分组,并使用 Java 8 Stream 按周查找每个分组值的最大值。

  • 我目前有在那里我可以不是关键放回转换问题LocalDate流中的对象,由于这样的事实,我没有必要的数据字段创建的对象LocalDate入地图。

  • 如果我不将其转换为LocalDate并将其保留为String ,则无法使用TreeMap使用键以自然顺序排列键值。

  • 如果我在对数据进行分组时不将月份包含在DateTimeFormatter.ofPattern ,那么两年之间的周数可能会重叠。

  • 如果我只使用周数整数作为流中地图的输出,则按周分组的值将与另一年的周数混合并重叠,即 2020-2021 与第 1 周。

题:

  • 如何使用java流获得每周值的最大值?

  • 如何将密钥字符串格式化为LocalDate并且仅将数周、数月LocalDate年作为流的输出?

数据集:

这是地图中实际数据的一小部分。 的实际日期输入到地图具有介于2020-01-152021-08-16和它们一起在地图其不是唯一的各累积整数唯一的

Map<LocalDate,Integer> CumulativeGarbageWasteDate = new HashMap<LocalDate,Integer>();
    CumulativeGarbageWasteDate.put(LocalDate.parse(("5/2/2020"),DateTimeFormatter.ofPattern("[M/d/yyyy][M/d/yy]")),2400);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("12/24/20"),DateTimeFormatter.ofPattern("M/d/yy")),140);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("5/2/20"),DateTimeFormatter.ofPattern("M/d/yy")),2400);
    
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/1/21"),DateTimeFormatter.ofPattern("M/d/yy")),182);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/2/21"),DateTimeFormatter.ofPattern("M/d/yy")),203);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/3/21"),DateTimeFormatter.ofPattern("M/d/yy")),321);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/3/21"),DateTimeFormatter.ofPattern("M/d/yy")),421);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("5/2/2021"),DateTimeFormatter.ofPattern("[M/d/yyyy][M/d/yy]")),2400);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/6/21"),DateTimeFormatter.ofPattern("M/d/yy")),1200);
    CumulativeGarbageWasteDate.put(LocalDate.parse(("01/31/21"),DateTimeFormatter.ofPattern("M/d/yy")),2400);

代码:

private static Map<LocalDate, Integer> sumByWeek (Map<LocalDate,Integer> CumulativeGarbageWasteDate){
    
    DateTimeFormatter formatter3 = new DateTimeFormatterBuilder().appendPattern("w/M/YY").parseDefaulting(ChronoField.DAY_OF_WEEK,DayOfWeek.FRIDAY.getValue()).toFormatter();
    

    return CumulativeGarbageWasteDate
            .entrySet()
            .stream()
            .collect(Collectors.groupingBy(
                    row-> LocalDate.parse(row.getKey().format(DateTimeFormatter.ofPattern("w/M/YY")),formatter3),
                    TreeMap::new,
                    Collectors.reducing(0, x->x.getValue(),Math::max)));
}

错误:

这是我在运行代码时遇到的错误。

java.time.format.DateTimeParseException: Text '5/2/20' could not be parsed: Conflict found: Field MonthOfYear 1 differs from MonthOfYear 2 derived from 2020-01-31

尝试:

我已经尝试使用这些代码行来替换上面的行代码行,可惜它不起作用或者它不是我需要的对象类型。

row-> (row.getKey().format(DateTimeFormatter.ofPattern("w/M/YY"))),
row-> LocalDate.parse(row.getKey().format(DateTimeFormatter.ofPattern("w/M/YY")),formatter),

预期输出:

以下是打印地图时的预期输出:[年/月/年的周数=分组周值中的最高值]

{50/12/19=140,1/1/20=421,2/1/20=1200}

输出地图的类型为Map<LocalDate, Integer> ,其中键是该周具有最高值的日期。 (我正在拆分解决方案以使其更易于理解)。

首先,我建议创建一个类(可能是一个内部类)来保存日期及其相应的值。 这将使处理变得容易。

private static class MyData {
    private LocalDate date;
    private int value;
    
    // getters and a constructor
}

注意:假设在下面的代码中为Collectors方法(如groupingtoMaptoListmapping进行静态导入。

可以使用WeekFields检索一年中的第WeekFields 。(请参阅

WeekFields weekFields = WeekFields.of(Locale.getDefault());

// function to generate a key of the form: week~year. year included to avoid overlap
Function<Entry<LocalDate, Integer>, String> groupFn 
    = row -> String.format("%d~%d",
                           row.getKey().get(weekFields.weekOfWeekBasedYear()),
                           row.getKey().getYear());

现在将输入转换为MyData对象:

Map<String, List<MyData>> temp = 
    input.entrySet()
         .stream()
         .collect(groupingBy(groupFn,
                             TreeMap::new, 
                             mapping(e -> new MyData(e.getKey(), e.getValue()), toList())));

现在我们找到一周内最大值的日期:

Function<Entry<String, List<MyData>>, MyData> maxDataFn 
    = entry -> entry.getValue()
                    .stream()
                    .collect(collectingAndThen(maxBy(Comparator.comparingInt(MyData::getValue)),
                                               Optional::get));

TreeMap<LocalDate, Integer> result 
    = temp.entrySet()
          .stream()
          .map(maxDataFn)
          .collect(toMap(MyData::getDate, MyData::getValue, Integer::max, TreeMap::new));

appendPattern("w/M/YY")更改为appendPattern("dd/MM/yyy)并将ofPattern("w/M/YY")更改为ofPattern(dd/MM/yyyy")

使用 LocalDate 的parse()方法。 LocalTime 类的parse()方法用于从作为参数传递的字符串(例如2002-02-21获取 LocalTime 的实例。该字符串必须具有有效的日期时间并使用DateTimeFormatter.ISO_LOCAL_DATE进行解析。 使用DateTimeFormatter正确格式化日期字符串。

下面是例子

import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class MyClass {
    public static void main(String args[]) {
    Map<LocalDate, Double> map = new HashMap<>();
    DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd");
    LocalDate date1 = LocalDate.parse("2002/02/21", df);
    LocalDate date2 = LocalDate.parse("2003/02/21", df);
    
    map.put(date1, 12.4);
    map.put(date2, 14.4);
    
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM