元素可重复的 Set -- Multiset

2017-04-05 19:06:27   最后更新: 2017-04-05 19:06:27   访问数量:298




此前我们曾经介绍过,java 提供了丰富的容器类来解决一组对象的管理问题:

Collection 及其相关实现的容器简介及用法

Map 简介及用法

但是对于复杂的情况,jdk 提供的容器类还是显得有些不足,guava 引入了一系列新的集合类,来扩充 JDK 集合框架,令人欣慰的是,guava 的集合接口完全遵循了 jdk 的思想和理念

 

众所周知,jdk 的 Set 是一个继承自 Collection 的接口,用于实现不重复的元素的集合,但有时,我们是很需要一个值能够重复的 Set 的,最常见的需求就是我们需要集合中不重复的元素的集合,那么我们需要一个 Set,但是我们还需要知道集合中各个元素的出现次数,那么 Set 就无法做到了,仅适用 List 也是难以满足的,非要实现的话,代码的复杂度就会变得很高而不易于维护

Guava 提供的 Multiset 解决了上述问题,简单地说,Multiset 提供了一个元素可重复的 Set,事实上,这在 C++ 的 STL 中早已有所提供,大概 java 的作者认为这个集合的功能通过 Map 或 ArrayList 完全可以实现,所以就没有将这个集合放入到 jdk 中吧

 

Multiset 是一个接口,提供了以下方法:

Multiset 提供的方法
方法说明
int count(E e)集合中元素 e 的个数
int add(E e, int count)增加集合中元素 e 的计数
int remove(E e, int count)减少集合中元素 e 的计数
int setCount(E e, int count)将集合中元素 e 的计数设置为 count 值,若 count 值为 0 则删除元素 e
boolean setCount(E e, int oldCount, int newCount)若集合中元素 e 的计数是 oldCount 则设置为 newCount,否则返回 false
Set elementSet()返回包含集合中全部元素的 Set
Set> entrySet()返回用于遍历的 Multiset.Entry Set

 

由于 Multiset 接口继承自 Collection 接口,因此,Collection 中的所有方法 Multiset 也都具备,但是,诸如 size()、iterator() 等方法或直接遍历,都会将 Multiset 看作一个元素可重复的集合,而不再是一个 Set

 

与 Map.Entry 类似,Multiset 也拥有自己用于遍历的 Entry 类型,它包含两个字段:

  1. element -- 元素
  2. count -- 计数

 

Guava 提供了多种 Multiset 的实现,与 JDK 中 Map 的各种实现非常类似:

  1. HashMultiset
  2. TreeMultiset
  3. LinkedHashMultiset
  4. ConcurrentHashMultiset
  5. ImmutableMultiset
  6. ImmutableSortedMultiset

 

值得一提,SortedMultiset 是一个 Multiset 的变种,通过他的 subMultiset 方法可以获取一个 Multiset 集合,这个方法用来返回集合中某个范围的全部元素

例如,latencies.subMultiset(0, BoundType.CLOSED, 100, BoundType.OPEN) 返回了站点中延迟在 100 毫秒以内的访问,通过得到的 Multiset 对象的 elementSet 方法就可以看到每一个请求了

 

考虑我们拥有一个“水果”字符数组,我们需要知道每种水果的个数,那么我们需要怎么来处理呢?

 

Map 版本

package com.techlog.test.testspring.service; import java.util.HashMap; import java.util.Map; /** * Created by techlog on 2017/4/3. */ public class WorkMain { public static void main(String[] argv) { String[] frutes = {"apple", "bnana", "watermallon", "apple", "apple", "bnana", "apple", "orange"}; Map<String, Integer> frutesCount = new HashMap<>(); for (String frute : frutes) { Integer count = frutesCount.get(frute); if (count == null) { count = 0; } frutesCount.put(frute, ++count); } for (Map.Entry<String, Integer> entry : frutesCount.entrySet()) { System.out.println(entry.getKey() + " : " + entry.getValue()); } } }

 

 

Multiset 版本(elementSet 方法遍历)

package com.techlog.test.testspring.service; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import java.util.Collections; /** * Created by techlog on 2017/4/3. */ public class WorkMain { public static void main(String[] argv) { String[] frutes = {"apple", "bnana", "watermallon", "apple", "apple", "bnana", "apple", "orange"}; Multiset<String> stringMultiset = HashMultiset.create(); Collections.addAll(stringMultiset, frutes); for (String frute : stringMultiset.elementSet()) { System.out.println(frute + " : " + stringMultiset.count(frute)); } } }

 

 

Multiset 版本(entrySet 方法遍历)

package com.techlog.test.testspring.service; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import java.util.Collections; /** * Created by techlog on 2017/4/3. */ public class WorkMain { public static void main(String[] argv) { String[] frutes = {"apple", "bnana", "watermallon", "apple", "apple", "bnana", "apple", "orange"}; Multiset<String> stringMultiset = HashMultiset.create(); Collections.addAll(stringMultiset, frutes); for (Multiset.Entry<String> fruteEntry : stringMultiset.entrySet()) { System.out.println(fruteEntry.getElement() + " : " + fruteEntry.getCount()); } } }

 

 

显然,Multiset 的版本要简洁不少

 






技术帖      龙潭书斋      java      jdk      set      集合      collection      map      entry      guava     


京ICP备15018585号