Guava學習總結之 - 7 - Collections - New collection types

Guava在繼承的基礎上創建了一些的新的集合類型,這些新的集合類型不是強化版的JDK集合類型,也不是用來完全替代JDK類型的,他們是設計用來完成一些特殊用途的。 


Multiset

如果我們需要記載一個字符串出現的次數,最平常的做法如下

Map<String, Integer> counts = new HashMap<String, Integer>();
for (String word : words) {
 
Integer count = counts.get(word);
 
if (count == null) {
    counts
.put(word, 1);
 
} else {
    counts
.put(word, count + 1);
 
}
}

這樣顯得代碼臃腫且易錯,Multiset的引入正是爲了解決這個問題,和普通的Set不同的是對於每個存在於Multiset存在的元素,Multiset還保存了一分這個元素出現的次數。所以上面代碼改變爲:

HashMultiset<String>

由於Multiset是一個集合,它也包含了例如add(E), size(), iterator()等基本操作同時,它特有的方法包括

count(E) 元素出現的次數

elementSet() 返回元素E的Set<E> 版本

add(E, int)  增加元素的出現次數

remove(E, int) 減少元素的出現次數

setCount(E, int) 設置元素的出現次數


Multiset有多個JDK集合的對應實現

Map                              Corresponding Multiset Supports null elements

HashMap                HashMultiset                             Yes

TreeMap                        TreeMultiset                             Yes (if the comparator does)

LinkedHashMap        LinkedHashMultiset             Yes

ConcurrentHashMap   ConcurrentHashMultiset     No

ImmutableMap         ImmutableMultiset No


SortedMultiset

是一個Multiset的變種,它可以很方便的查處在一定範圍內的元素出現的整體格式,例如

SortedMultiset.subMultiset(0, BoundType.CLOSED, 100, BoundType.OPEN).size() 可以放我們知道 0-100 數字在整個區間出現的次數。



Multimap

在平時我們在某些時候會用到類似 Map<K, List<V>> or Map<K, Set<V>> 的數據結構,爲這樣的數據結構書寫代碼也很不方便,Multimap很好的解決了這個問題, 請看下例

ArrayListMultimap<String,String> multiMap = ArrayListMultimap.create();
multiMap.put("Bar","1");
multiMap.put("Bar","2");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
結果 a -> [1,2,3,3,3]
size()結果5

HashMultimap<String,String> multiMap = HashMultimap.create();
multiMap.put("Bar","1");
multiMap.put("Bar","2");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
結果 a -> [1,2,3]
size()結果3

我們也可以用Multimap.get(key)得到對應的集合從而直接操作。 需要注意的事情

  • Multimap.entries() 返回所有的鍵值對,例如上例,將會返回<Bar,1>,<Bar,2>,<Bar,3>,<Bar,3>,<Bar,3>. 如果想得到鍵的集合,需要用Multimap.asMap().keySet()

  • Multimap.size() 返回所有鍵值對的個數。


Multimap 也有不用的實現主要是實現的集合不一樣:

Implementation           Keys behave like...   Values behave like..

ArrayListMultimap            HashMap                   ArrayList

HashMultimap            HashMap                   HashSet

LinkedListMultimap*    LinkedHashMap*    LinkedList*

LinkedHashMultimap**     LinkedHashMap    LinkedHashSet

TreeMultimap                     TreeMap                     TreeSet

ImmutableListMultimap     ImmutableMap              ImmutableList

ImmutableSetMultimap      ImmutableMap              ImmutableSet


 

BiMap

某些時候,我們需要通過鍵找到值, 也同時需要通過值找到鍵。普通的做法是用兩個Map還維護

Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();

nameToId
.put("Bob", 42);
idToName
.put(42, "Bob");
// what happens if "Bob" or 42 are already present?
// weird bugs can arise if we forget to keep these in sync...

這個問題可以通過Bimap優雅的實現

BiMap<String, Integer> userId = HashBiMap.create();
...

String userForId = userId.inverse().get(id);


Table

現實中需要用到Table數據結構的情形筆筆皆是 ,其用法非常直觀簡單,請看一下用法

HashBasedTable<Integer,Integer,String> table = HashBasedTable.create();
table.put(1,1,"Rook");
table.put(1,2,"Knight");
table.put(1,3,"Bishop");

boolean contains11 = table.contains(1,1);
boolean containColumn2 = table.containsColumn(2);
boolean containsRow1 = table.containsRow(1);
boolan containsRook = table.containsValue("Rook");

table.remove(1,3);
table.get(3,4);


Map<Integer,String> columnMap = table.column(1);
Map<Integer,String> rowMap = table.row(2);

Table 的一些實現


HashBasedTable 後臺由HashMap<R, HashMap<C, V>>支持

TreeBasedTable, 後臺由 TreeMap<R, TreeMap<C, V>>支持

ImmutableTable, 後臺由 ImmutableMap<R, ImmutableMap<C, V>>支持, 對於稀疏或者高密度數據效率好一些

ArrayTable, 後臺由二維數組支持,創建的時候需要制定行和列長度。


ClassToInstanceMap

這個集合很奇葩基本上就是 Map<Class, Object> 的翻版, 例如

ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults
.putInstance(Integer.class, Integer.valueOf(0));

需要注意的是ClassToInstanceMap<B> implements Map<Class<? extends B>, B>, 也就是Map裏面的key值必須是ClassToInstanceMap定義類型的子類類型。


RangeSet

顧名思義,RangeSet包含了範圍的集合,這些範圍是非空的,且可以是不連續的,上個例子先:

 RangeSet<Integer> rangeSet = TreeRangeSet.create();
   rangeSet
.add(Range.closed(1, 10)); // {[1, 10]}
   rangeSet
.add(Range.closedOpen(11, 15)); // disconnected range: {[1, 10], [11, 15)}
   rangeSet
.add(Range.closedOpen(15, 20)); // connected range; {[1, 10], [11, 20)}
   rangeSet
.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 20)}
   rangeSet
.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}

常用方法:

  • contains(C) 最基本操作, 查看一個element 是否在範圍之內

  • rangeContaining(C):查看是哪一個range 包含了range. 沒有就返回null

  • encloses(Range<C>): 判斷一段範圍是否在rangeset之類

  • span(): 返回一個包含了set所有區間的最小的range


RangeMap

比較簡單,直接見例子:

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap
.put(Range.closed(1, 10), "foo"); // {[1, 10] => "foo"}
rangeMap
.put(Range.open(3, 6), "bar"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 10] => "foo"}
rangeMap
.put(Range.open(10, 20), "foo"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 10] => "foo", (10, 20) => "foo"}
rangeMap
.remove(Range.closed(5, 11)); // {[1, 3] => "foo", (3, 5) => "bar", (11, 20) => "foo"}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章