2017-05-05 64 views
2

支持我有一個數據模型,看起來像這樣的地圖:如何生成一個列表

class CustomField { 
    String key; 
    String value; 
} 

從一個API,我可以得到的List<CustomField>實例。密鑰在列表中是唯一的,這意味着這個集合應該是Map<String, String>。在這個列表上操作是一件很痛苦的事情,因爲每個操作都需要迭代來檢查現有密鑰(CustomField不會實現等於)

如何創建一個支持此列表的Map<String, String>「視圖」,以便我可以操作使用地圖界面?

我想要一個通用的方法,如:<T, K, V> Map<K, V> createMapBackedByList(List<T> list, BiFunction<K, V, T> elementMapper, Function<T, K> keyMapper, Function<T, V> valueMapper)或類似的。

它將使用函數來映射列表元素和映射鍵和值之間的映射。

這裏最重要的是,我想更改地圖的基礎列表中得到體現,這就是爲什麼流API不在這裏工作了......

編輯:我不能修改API或CustomField類。

+0

爲什麼你不只是製造了一個'地圖'從'名單',把它放回了'List'大功告成後?你真的需要直接改變底層結構嗎? – Jack

+0

也許你可以通過'map.values()'得到地圖的值列表。 – Colliot

+0

您可以編寫一個新的'Map'實現,可能會擴展['AbstractMap'](https://docs.oracle.com/javase/7/docs/api/java/util/AbstractMap.html)。 – khelwood

回答

1

我最終試圖自己實現它並將其基於AbstractList。它實際上是更容易比我第一次,雖然...

public class ListBackedMap<T, K, V> extends AbstractMap<K, V> { 
    private final List<T> list; 
    private final BiFunction<K, V, T> keyValueToElement; 
    private final Function<T, K> elementToKey; 
    private final Function<T, V> elementToValue; 

    public ListBackedMap(List<T> list, BiFunction<K, V, T> keyValueToElement, Function<T, K> elementToKey, Function<T, V> elementToValue) { 
     this.list = list; 
     this.keyValueToElement = keyValueToElement; 
     this.elementToKey = elementToKey; 
     this.elementToValue = elementToValue; 
    } 

    @Override 
    public Set<Entry<K, V>> entrySet() { 
     return list.stream() 
       .collect(toMap(elementToKey, elementToValue)) 
       .entrySet(); 
    } 

    @Override 
    public V put(K key, V value) { 
     V previousValue = remove(key); 
     list.add(keyValueToElement.apply(key, value)); 
     return previousValue; 
    } 

    public List<T> getList() { 
     return list; 
    } 
} 

這不是很高性能的(或線程安全的),但似乎做的工作不夠好。

例子:

List<CustomField> list = getList(); 
ListBackedMap<CustomField, String, String> map = new ListBackedMap<>(
     list, 
     (key, value) -> new CustomField(key, value), 
     CustomField::getKey, 
     CustomField::getValue); 
+0

我很高興我能指出你的方向。爲了「完成」你的例子,你可能想要展示如何實例化這個類(假設你正在使用各種lambdas來從字段到鍵/值的「映射」)。至少我;我很好奇你是怎麼做到的;-) – GhostCat

+0

我想這也適用於Set,前提是元素相等是基於關鍵的。 –

+0

@GhostCat更新了一個例子:) –

3

簡單:

寫自己的

public class ListBackedMap<K, V> implements Map<K, V> { 

這需要某種List<Pair<K,V>>上創造;並「推遲」這一點。當然,這要求您的CustomField類實現該接口。 (你可能需要發明它)

(或者:你的新班級extends AbstractMap<K,V>爲了您的大部分工作安全)。

現在你的方法只是返回這樣一個Map的一個實例。

換句話說:我不知道內置的包裝符合您的要求。但是自己實施一個應該非常簡單。

編輯:給定的事實,OP不能改變CustomField類,一個簡單的輔助,例如

interface <K, V> MapEntryAdapter { 
    K getKey(); 
    V getValue(); 
} 

將需要;以及知道如何從CustomField的實例中檢索密鑰/值的特定實現。在這種情況下,地圖將由List<MapEntryAdapter<K, V>>支持。

+0

當然,這是完全可能的,但不是微不足道的,我希望在任何流行的集合框架(如Google Guava或Apache Commons)中找到類似的東西。 我無法更改CustomField,因此Pair解決方案不存在問題... –

+0

我可以幫助Pair對象 - 因爲該構造不是必需的;我們只需添加*另一層抽象(總是有助於解決問題)。查看我的更新。 – GhostCat

+0

我接受了關於擴展AbstractMap的建議,最終它實際上很簡單。請參閱http://stackoverflow.com/a/43805008/940731 –