反转具有冗余值的地图以生成多图 [英] Invert a Map with redundant values to produce a multimap
问题描述
给出一个这样的地图,其中我们有一年中每周的频率计数:
Given a map such as this where we have a frequency count per day-of-week for a year:
Map.of(
DayOfWeek.MONDAY , 52 ,
DayOfWeek.TUESDAY , 52 ,
DayOfWeek.WEDNESDAY, 53 ,
DayOfWeek.THURSDAY , 53 ,
DayOfWeek.FRIDAY , 52 ,
DayOfWeek.SATURDAY , 52 ,
DayOfWeek.SUNDAY , 52
)
...或作为文本:
{MONDAY = 52,TUESDAY = 52,WEDNESDAY = 53,THURSDAY = 53,FRIDAY = 52,SATURDAY = 52,SUNDAY = 52}
{MONDAY=52, TUESDAY=52, WEDNESDAY=53, THURSDAY=53, FRIDAY=52, SATURDAY=52, SUNDAY=52}
...我如何可以反转生成一个具有不同编号的多重地图,每个数字都会导致一个集合(list?set?)拥有该号码的 DayOfWeek
?
…how can I invert to produce a multimap of distinct numbers each leading to a collection (list? set?) of the DayOfWeek
which owned that number?
结果应等于以下代码的结果:
The result should be equivalent to the result of this code:
Map.of(
53 , List.of( DayOfWeek.WEDNESDAY , DayOfWeek.THURSDAY ) ,
52 , List.of( DayOfWeek.MONDAY , DayOfWeek.TUESDAY , DayOfWeek.FRIDAY , DayOfWeek.SATURDAY , DayOfWeek.SUNDAY )
)
我想使用直接的Java生成结果 multimap ,而无需使用诸如 Eclipse集合 或 Guava:通过反转地图构建多图 .考虑到现代Java中的新流和多图功能,我希望现在可以实现,而那时还没有.
I would like to produce the resulting multimap using straight Java without extra libraries such as Eclipse Collections or Google Guava. Those libraries might make this easier, but I am curious to see if a solution using only built-in Java is possible. Otherwise, my Question here is the exact same Question as Guava: construct a Multimap by inverting a Map. Given new streams and multimap features in modern Java, I expect this is possible now while it was not then.
我看到了许多与此类似的现有问题.但是,没有一个适合我的情况,这似乎是很普遍的情况.例如,此问题忽略了原始值是冗余/多个的问题,因此必须使用多重映射.其他如此或此涉及Google Guava.
I saw various existing Questions similar to this. But none fit my situation, which seems like a rather common situation. For example, this Question neglects the issue of the original values being redundant/multiple, thus necessitating a multimap as a result. Others such as this or this involve Google Guava.
推荐答案
以下使用Java 9或更高版本的作品:
The following works using Java 9 or above:
@Test
void invertMap()
{
Map<DayOfWeek, Integer> map = Map.of(
DayOfWeek.MONDAY, 52,
DayOfWeek.TUESDAY, 52,
DayOfWeek.WEDNESDAY, 53,
DayOfWeek.THURSDAY, 53,
DayOfWeek.FRIDAY, 52,
DayOfWeek.SATURDAY, 52,
DayOfWeek.SUNDAY, 52
);
Map<Integer, Set<DayOfWeek>> flipped = new TreeMap<>();
map.forEach((dow, count) ->
flipped.computeIfAbsent(count, (key) ->
EnumSet.noneOf(DayOfWeek.class)).add(dow));
Map<Integer, Set<DayOfWeek>> flippedStream = map.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getValue,
TreeMap::new,
Collectors.mapping(
Map.Entry::getKey,
Collectors.toCollection(
() -> EnumSet.noneOf(DayOfWeek.class)))));
Map<Integer, Set<DayOfWeek>> expected = Map.of(
53, EnumSet.of(
DayOfWeek.WEDNESDAY,
DayOfWeek.THURSDAY),
52, EnumSet.of(
DayOfWeek.MONDAY,
DayOfWeek.TUESDAY,
DayOfWeek.FRIDAY,
DayOfWeek.SATURDAY,
DayOfWeek.SUNDAY)
);
Assert.assertEquals(expected, flipped);
Assert.assertEquals(expected, flippedStream);
}
如果您愿意使用第三方库,则下面的代码将与 Eclipse Collections :
If you are open to using a third-party library, the following code will work with Eclipse Collections:
@Test
void invertEclipseCollectionsMap()
{
MutableMap<DayOfWeek, Integer> map =
Maps.mutable.<DayOfWeek, Integer>empty()
.withKeyValue(DayOfWeek.MONDAY, 52)
.withKeyValue(DayOfWeek.TUESDAY, 52)
.withKeyValue(DayOfWeek.WEDNESDAY, 53)
.withKeyValue(DayOfWeek.THURSDAY, 53)
.withKeyValue(DayOfWeek.FRIDAY, 52)
.withKeyValue(DayOfWeek.SATURDAY, 52)
.withKeyValue(DayOfWeek.SUNDAY, 52);
SetMultimap<Integer, DayOfWeek> flipped = map.flip();
Assert.assertEquals(flipped.get(52), Set.of(
DayOfWeek.MONDAY,
DayOfWeek.TUESDAY,
DayOfWeek.FRIDAY,
DayOfWeek.SATURDAY,
DayOfWeek.SUNDAY));
Assert.assertEquals(flipped.get(53), Set.of(
DayOfWeek.WEDNESDAY,
DayOfWeek.THURSDAY));
}
注意:我是Eclipse Collections的提交者.
Note: I am a committer for Eclipse Collections.
这篇关于反转具有冗余值的地图以生成多图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!