2011-04-20 116 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))); 
相關問題