假设我有一个整数数据映射,其中键是日期和时间,格式如下:
2015年5月15日下午5:46
例如,我有:
2015年5月15日下午5:46,25 2015年5月15日下午5点50分,25周年 2015年5月15日下午6:15,30 2015年5月15日8:05 PM,40
2015年5月15日10:46 PM,10
2015年5月15日上午5点10分,5周
有没有办法按小时对这些数据进行排序?所以我可以有类似的东西:
下午5点,55周 下午6点30分 晚上8点,40 晚上10点,10日
日期也一样吗?
答案 0 :(得分:2)
Map<String, Integer> originalMap = ... // the map you mentioned
Map<String, Integer> aggregationMap = new HashMap<String, Integer>();
DateFormat sdf = new SimpleDateFormat("MMM dd, yyyy hh:mm a", Locale.US);
// change "ha" to "yyyyMMdd" if you wanna do aggregation by date
DateFormat sdf2 = new SimpleDateFormat("ha", Locale.US);
Iterator<String> it = originalMap.keySet().iterator();
while (it.hasNext()) {
String k = it.next();
int v = originalMap.get(k);
String key = sdf2.format(sdf.parse(k));
Integer value = aggregationMap.get(key);
if (value == null) {
aggregationMap.put(key, v);
} else {
aggregationMap.put(key, v + value);
}
}
// TODO dump aggregationMap to see the result
答案 1 :(得分:0)
假设您正在使用java.util.Map
的实现类,我认为这样做的最好方法是:
entrySet()
方法获取地图条目集。 Comparator
类,按小时按升序对日期时间条目进行排序。另外,你可以写一个按日期排序。SortableSet
初始化TreeSet的构造函数创建TreeSet(Comparator
的实现)。TreeSet.addAll()
复制和排序您在步骤1中获得的Set<Map.Entry>
条目。或者,如果您不想创建与现有地图完全相同的数据结构,则可以获取keySet
并仅对键进行排序。然后,当您想按顺序访问地图元素时,您可以遍历已排序的keySet
并将相应的数字拉出已有的地图。
答案 2 :(得分:0)
首先,我假设您的原始数据存储在Map<String, Integer>
中,该rawData
是名为<T extends Comparable<? super T> & Temporal> SortedMap<T, Integer> summarize(
DateTimeFormatter keyFormat,
Function<LocalDateTime, ? extends T> keyTransform)
{
SortedMap<T, Integer> summaryData = new TreeMap<>();
rawData.forEach((k, v) -> {
LocalDateTime rawDateTime = LocalDateTime.parse(k, keyFormat);
T summaryKey = keyTransform.apply(rawDateTime);
summaryData.merge(summaryKey, v, (x, y) -> x + y);
});
return summaryData;
}
的成员字段。使用Java 8,这是您所需的聚合摘要和排序逻辑的核心:
rawData
此方法处理Temporal
映射并返回其键为LocalDate
类型的有序映射 - 例如,没有时间组件的LocalTime
或{{1}没有日期组件。为了确定哪种行为,您必须传入两个参数:
String
键解释为LocalDateTime
。LocalDateTime
转换为您所需的粒度级别的聚合键。对summaryData.merge(...)
的调用负责第一次添加密钥和值;当同一个键再次合并时,提供的lambda表达式结合了先前值和新值 - 在您的情况下,您只想添加两个值。
密钥类型(例如LocalDate
)也必须是Comparable
,以便排序的地图实现将自动进行排序。这是一个帮助方法,它使用上面的方法在您的问题中按小时生成所需的输出。仍需要原始数据密钥格式化程序作为输入:
void printSummaryByHour(DateTimeFormatter rawKeyFormat)
{
SortedMap<LocalTime, Integer> summary =
summarize(
rawKeyFormat,
key -> LocalTime.of(key.getHour(), 0) // ignore date, minutes, seconds, etc.
);
DateTimeFormatter summaryKeyFormat =
DateTimeFormatter.ofPattern("h a", Locale.US); // e.g. "7 PM"
print(summary, summaryKeyFormat::format);
}
对summarize
方法的调用使用 lambda表达式将LocalDateTime
映射到始终忽略分钟值的LocalTime
(删除日期)只保留时间。然后它将生成的有序集传递给我稍后将要覆盖的方法输出到控制台,但很可能你的真实程序不仅要打印到屏幕上。
您的问题没有给出您预期输出的示例&#34;按日期&#34;,所以我假设您想要离散的日子,例如&#34; 2015年5月15日和#34 ;并且不会在几个月或任何特殊情况下汇总 - 只需总结整个24小时的时间段。使用上述方法的不同版本可以轻松完成此操作,仅更改摘要键类型,摘要转换和输出格式:
void printSummaryByDate(DateTimeFormatter rawKeyFormat)
{
SortedMap<LocalDate, Integer> summary =
summarize(
rawKeyFormat,
LocalDateTime::toLocalDate
);
DateTimeFormatter summaryKeyFormat =
DateTimeFormatter.ofPattern("MMMM dd, yyyy", Locale.US); // e.g. "May 15, 2015"
print(summary, summaryKeyFormat::format);
}
现在,排序后的地图由LocalDate
代替LocalTime
。从日期时间到日期的密钥转换仅使用函数引用而不是自定义lambda表达式,并且摘要键的输出格式也相应地更改。
要完成答案,请参阅设置脚手架和print
辅助方法:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.*;
import java.util.function.Function;
public class StackOverflow30494397
{
private final Map<String, Integer> rawData = new HashMap<>();
public static void main(String... args)
{
StackOverflow30494397 instance = new StackOverflow30494397();
instance.rawData.put("May 15, 2015 5:46 PM", 25);
instance.rawData.put("May 15, 2015 5:50 PM", 25);
instance.rawData.put("May 15, 2015 6:15 PM", 30);
instance.rawData.put("May 15, 2015 8:05 PM", 40);
instance.rawData.put("May 15, 2015 10:46 PM", 10);
instance.rawData.put("May 15, 2015 5:10 AM", 5);
DateTimeFormatter rawKeyFormat =
DateTimeFormatter.ofPattern("MMMM dd, yyyy h:mm a", Locale.US);
instance.printSummaryByHour(rawKeyFormat);
instance.printSummaryByDate(rawKeyFormat);
}
private <K> void print(Map<K, ?> map, Function<? super K, String> keyFormatter)
{
map.forEach((k, v) -> System.out.printf("%s, %d%n", keyFormatter.apply(k), v));
System.out.println();
}
// INSERT OTHER METHODS (DESCRIBED IN ANSWER) HERE
}
输出:
凌晨5点,5 下午5点,50
下午6点30 晚上8点,40
晚上10点,10日2015年5月15日,135