如何将Map <string,string =“”>转换为Map <long,string =“”>? (选项:使用番石榴)</long,> </string,>

时间:2011-04-20 15:52:22

标签: java guava

我有Map<String, String> String键只是数字值,如“123”等。我得到数值,因为这些值来自我的JSF组件中的UI。我不想更改UI组件的合同。

现在我想基于上面的Map<Long, String>创建一个Map,我在transform类中看到了一些Maps方法但是所有方法都专注于转换值而不是关键。

有没有更好的方法将Map<String, String>转换为Map<Long, String>

7 个答案:

答案 0 :(得分:39)

@Vivin的答案是正确的,但我认为解释为什么Guava没有任何方法允许你转换Map的键(或者转换Set根本没用)。

Guava用于转换和过滤的所有方法都会产生延迟结果......函数/谓词仅在需要时应用,因为使用了对象。他们不创建副本。因此,转换很容易打破Set的要求。

例如,假设您有Map<String, String>包含“1”和“01”作为键。它们都是不同的String s,因此Map可以合法地包含两个键。但是,如果使用Long.valueOf(String)转换它们,它们都会映射到值1。它们不再是不同的关键。如果您创建地图副本并添加条目,则不会破坏任何内容,因为任何重复的密钥都将覆盖该密钥的上一个条目。但是,一个懒惰变换后的Map无法强制执行唯一键,因此会违反Map的合同。

答案 1 :(得分:23)

现在,您可以使用Java 8流,map,collect以更易读,更干净的方式执行此操作。

Map<String, String> oldMap

Map<Long, String> newMap = oldMap.entrySet().stream()
  .collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), Map.Entry::getValue));

答案 2 :(得分:16)

Java 8更新

您可以使用流来执行此操作:

Map<Long, String> newMap = oldMap.entrySet().stream()
  .collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue));

这假设所有密钥都是Long s的有效字符串表示。此外,转换时可能会发生冲突;例如,"0""00"都映射到0L


我认为你必须遍历地图:

Map<Long, String> newMap = new HashMap<Long, String>();
for(Map.Entry<String, String> entry : map.entrySet()) {
   newMap.put(Long.parseLong(entry.getKey()), entry.getValue());
}

此代码假定您已清理map中的所有值(因此没有无效的长值)。

我希望有更好的解决方案。

修改

我遇到了Commons Collection-Utils中的CollectionUtils#transformedCollection(Collection, Transformer)方法,看起来它可能会做你想要的。说来,它只适用于实现Collection的类

答案 3 :(得分:3)

以下是其中一个答案的更新版本,以使生成的Map无法修改(不,它不使用Guava,只是简单的Java 8):

  import static java.util.stream.Collectors.collectingAndThen;
  import static java.util.stream.Collectors.toMap;

  ...

  newMap = oldMap.entrySet().stream().collect(collectingAndThen(
              toMap((Map.Entry<String, String> entry) -> transformKey(entry.getKey()),
                    (Map.Entry<String, String> entry) -> transformValue(entry.getValue())),
              Collections::unmodifiableMap)));

答案 4 :(得分:2)

简短的回答是否定的,Guava没有开箱即用。

简单的方法就像下面这样。但是,有一些警告。

    public static <K, V, L, W> Map<L, W> transformMap(Map<K, V> map, Function<K, L> keyFunction, Function<V, W> valueFunction) {
    Map<L, W> transformedMap = newHashMap();

    for (Entry<K, V> entry : map.entrySet()) {
        transformedMap.put(
                keyFunction.apply(entry.getKey()),
                valueFunction.apply(entry.getValue()));
    }

    return transformedMap;
}

public static <K, V, L> Map<L, V> transformKeys(Map<K, V> map, Function<K, L> keyFunction) {
    return transformMap(map, keyFunction, Functions.<V>identity());
}

Guava的变形金刚都是“懒惰”或基于视图的。我想要实现一个地图密钥转换器,你需要一个双向功能。我的理解是,Guava团队正在开发一个转换器,可以解决这个问题。

你遇到的另一个问题是你必须处理重复的可能性才能成为另一种番石榴原则的“Jimmy-proof”。处理这种情况的一种方法是返回Multimap;另一种方法是在遇到重复时抛出异常。我不建议隐藏的问题,例如忽略具有重复键的后续条目,或者用重复键覆盖新条目。

答案 5 :(得分:0)

有史以来提供最佳工作解决方案的最佳文章:

Tranform HashMap in Java 8

此网站显示了所有3种可能的情况:

  1. 地图->地图
  2. 地图->地图
  3. 地图->地图

答案 6 :(得分:0)

使用Java 8和jOOλ

private static <K1, K2, V> Map<K2, V> mapKeys(Map<K1, V> map, Function<K1, K2> keyMapper) {
    return Seq.seq(map).map(t -> t.map1(keyMapper)).toMap(Tuple2::v1, Tuple2::v2);
}