2011-04-20 81 views
14

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

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

有没有更好的方法将Map<String, String>转换为Map<Long, String>如何将Map <String,String>转换为Map <Long,String>使用番石榴

+0

我不认为有一个内置功能为此。虽然我没有看到太多用处,但您可能需要[提交功能请求](http://code.google.com/p/guava-libraries/issues/list)。 – 2011-04-20 15:58:10

回答

11

更新的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值(所以没有无效的长值)。

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

编辑

我碰到在下议院收藏-utils的的CollectionUtils#transformedCollection(Collection, Transformer)方法看起来似乎你想要做什么来了。从头开始,它只适用于实现Collection的类。

+0

是的..这将是最后一种方法;) – Premraj 2011-04-20 15:55:47

+0

@Falcon :)即使有一个转换方法,内部实现将必须是类似的东西。即'O(n)'。我想不出有什么办法可以做到这一点,比“O(n)”更好。 – 2011-04-20 15:57:27

+2

这不是关于复杂性,但如果有东西已经写入,或者可以用番石榴的功能方法轻松实现(我已经写过函数),当然速度/效率相当,那么我不需要这样做。 – Premraj 2011-04-20 16:01:17

38

@ Vivin的回答是正确的,但我认为这有助于解释为什么番石榴没有任何方法让您转换Map(或转换Set)的密钥。

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

比方说,例如,您有一个包含“1”和“01”作为关键字的Map<String, String>。它们都是不同的String s,因此Map可以合法地包含这两个键。如果使用Long.valueOf(String)转换它们,则它们都映射到值1。他们不再是独特的钥匙。如果您创建映射副本并添加条目,这不会破坏任何内容,因为任何重复的键都会覆盖该键的前一个条目。然而,延迟变形的Map将无法​​执行唯一密钥,因此会破坏Map的合同。

+0

对不起,我直到后来才看到guava标签:p – 2011-04-20 18:14:30

2

简短的回答是不,番石榴不提供这个开箱即用。

简单的方法将如下所示。但是,有一些警告。

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团队正在开发一款Converter,它可以解决这个问题。

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

22

您现在可以使用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)); 
3

这里是下面的答案之一的更新版本,使生成的地图不可修改的(不,它不是用番石榴,只是普通的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))); 
相关问题