Java将{String,String}[]转换为Map<String,String[]>

3

给定以下类:

 public class CategoryValuePair
 {
      String category;
      String value;
 }

还有一个方法:

public Map<String,List<String>> convert(CategoryValuePair[] values);

考虑到在values中我们可能会收到许多具有相同类别的条目,我想将它们转换为以类别分组的Map

有没有一种快速/高效的方法来执行这个转换?


在代码行数方面快速/高效,还是在运行时间和性能方面快速/高效? - vodkhang
2
你使用 String[] 而不是 List<String> 在你的 map 中有什么特别的原因吗?我想不出很多理由,为什么数组会更好,就你的问题而言,按照我的思路,列表会使它变得更容易一些。 - Lauri Lehtinen
@vodkhang - 首先追求性能,代码行数只是额外的奖励。 - Marty Pitt
@lauri-lehtinen 有一个,但不是很好。针对此问题,我已将其更改为List<String>。谢谢! - Marty Pitt
4个回答

2
据我所知,没有比遍历值并将这些值放入映射中(例如某些预定义方法)更简单的方法。
Map<String, List<String>> map = new HashMap<String, List<String>>();
if (values != null) {
    for (CategoryValuePair cvp : values) {
      List<String> vals = map.get(cvp.category);
      if (vals == null) {
        vals = new ArrayList<String>();
        map.put(cvp.category, vals);
      }
      vals.add(cvp.value);
    }
}

我将地图的值从String[]更改为List<String>,因为我认为使用它更容易,这样您就不必担心数组调整大小的问题。


3
性能优化建议:只有在创建新列表时才将列表放入映射中。可参考以下代码实现:if (vals == null) { vals = new ArrayList<String>(); map.put(cvp.category, vals); } - user85421
我同意你的看法,Carlos。如果键已知,则put方法不会将值插入到映射中... - Fred
如果 values 取得了空值,你的代码会抛出 NullPointerException 异常。 - Fred

1
为了用更少的代码实现,可以使用Google Collections
public Map<String, Collection<String>> convert(CategoryValuePair[] values) {
    Multimap<String, String> mmap = ArrayListMultimap.create();
    for (CategoryValuePair value : values) {
        mmap.put(value.category, value.value);
    }
    return mmap.asMap();
}

如果您不想允许重复的值,请将 ArrayListMultimap 替换为 HashMultimap。

1

使用lambdaj,您只需要一行代码即可实现以下结果:

group(values, by(on(CategoryValuePair.class).getCategory()));

我是 lambdaj 项目的粉丝,该库已经在相关项目中。不知道为什么我之前没想到使用它。然而,就性能而言,我认为 Google Collections 的方法可能更快。(如果我错了请指出) - Marty Pitt
正如vodkhang所问,您是指“在代码行数方面快速/高效”还是“在运行时间和性能方面快速/高效”?如果您正在寻找一些非常易读且简洁的东西,我相信lambdaj可能是最佳解决方案(免责声明:我是lambdaj的创建者)。如果性能是您最关心的问题,即使lambdaj的组功能是最好的性能之一,您也应该选择Google Collection,正如您可以从项目文档中阅读的那样。我的最后建议是给两种解决方案一个机会,并编写一个小测试来比较它们的性能。让我知道您会发现什么。 - Mario Fusco

0
仅仅是为了实现而已... 这个方法返回一个Map,并且还会检查数组中是否有重复项... 尽管从性能方面来看它比较耗费资源...
public Map<String,String[]> convert(CategoryValuePair[] values)
{
    Map<String, String[]> map = new HashMap<String, String[]>();
    for (int i = 0; i < values.length; i++) {
        if(map.containsKey(values[i].category)){
            Set<String> set = new HashSet<String>(Arrays.asList(map.get(values[i].category)));
            set.add(values[i].value);
            map.put(values[i].category, set.toArray(new String[set.size()]));
        }else {
            map.put(values[i].category, new String[]{values[i].value});
        }
    }

    return map;
}

@Fred 嗯,它实际上编译成功了 :) - Favonius
因为您已经编辑了您的代码... 当我写下我的评论时,if子句并不存在... - Fred
哦,我必须……我使用了预格式和代码标签来格式化我的代码……这搞乱了一切……对于造成的混乱我很抱歉…… - Favonius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接