反转具有冗余值的地图以生成多图 [英] Invert a Map with redundant values to produce a multimap

查看:75
本文介绍了反转具有冗余值的地图以生成多图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出一个这样的地图,其中我们有一年中每周的频率计数:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆