新集合类型
Multiset
- 这里的集合[set]是数学上的概念.
- Multiset继承自JDK中的Collection接口,而不是Set接口,所以包含重复元素并没有违反原有的接口契约
先来一个实例,统计单词出现的次数java中的一般做法
@Test
public void testDemo() {
List<String> list = new ArrayList<>();
list.add("zs");
list.add("zs");
list.add("ls");
list.add("ww");
list.add("mz");
list.add("ls");
Map<String, Integer> c = new HashMap<>();
for (String word : list) {
Integer count = c.get(word);
c.put(word, (count == null) ? 1 : count + 1);
}
System.out.println("zs出现的次数: " + c.get("zs"));
}
使用Multiset
@Test
public void testMultiset() {
List<String> list = new ArrayList<>();
list.add("zs");
list.add("zs");
list.add("ls");
list.add("ww");
list.add("mz");
list.add("zs");
Multiset<String> multiset = HashMultiset.create(list);
System.out.println("zs出现的次数: "+multiset.count("zs"));
}
常用的方法
方法 | 描述 |
---|---|
count(E) | 指定元素的数量(例子中使用的方法) |
size | 返回集合元素的总个数(包括重复的元素) |
elementSet() | Multiset中不重复元素的集合,类型为Set |
entrySet() | 和Map的entrySet类似,返回Set<Multiset.Entry>,其中包含的Entry支持getElement()和getCount()方法 |
retainAll(Collectionc) | 保留出现在给定集合参数的所有的元素 |
removeAll(Collectionc) | 去除出现给给定集合参数的所有的元素 |
add(E, int) | 增加给定元素在Multiset中的计数 |
remove(E,int) | 减少给定元素在Multiset中的计数 |
setCount(E, int) | 设置给定元素在Multiset中的计数(不可以为负数) |
example
@Test
public void testMultiset() {
List<String> list = new ArrayList<>();
list.add("zs");
list.add("zs");
list.add("ls");
list.add("ww");
list.add("mz");
list.add("zs");
Multiset<String> multiset = HashMultiset.create(list);
//count(E)
System.out.println("zs出现的次数: "+multiset.count("zs"));
//size
System.out.println("multiset集合的个数: "+multiset.size());
//elementSet()
Set<String> set = multiset.elementSet();
System.out.println("multiset去重后的元素集合: "+set);
//entrySet()
Set<Multiset.Entry<String>> entries = multiset.entrySet();
for (Multiset.Entry<String> entry : entries){
System.out.println("单词: "+entry.getElement()+"出现的次数为: "+entry.getCount());
}
//removeAll(Collectionc)
multiset.removeAll(Arrays.asList("li"));
System.out.println("multiset集合的元素: "+multiset);
//retainAll(Collectionc)
multiset.retainAll(Arrays.asList("zs"));
System.out.println("multiset集合的元素: "+multiset);
//add(E, int)
multiset.add("ww",100);
System.out.println("multiset集合的元素: "+multiset);
//remove(E,int)
multiset.remove("ww",10);
System.out.println("multiset集合的元素: "+multiset);
//setCount(E, int)
multiset.setCount("ww",0);
System.out.println("multiset集合的元素: "+multiset);
}
上面我们讲述的是Multiset的HashMap实现
Multimap
先看一个实例: 用户信息根据年龄分组下面值一般的做法
public class GuavaMultiMapTest {
@Test
public void MultiMap() {
List<User> userList = new ArrayList<>();//假设是已经获取的用户信息集合
Map<String, List<User>> map = new HashMap<>();
List<User> temp = null;
for (User user : userList) {
temp = map.get(user.getAge());
if (temp == null) {
temp = new ArrayList<>();
temp.add(user);
}
temp.add(user);
}
}
}
class User {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
Multimap的实现(当然如果用java8 流实现也是可以的!)
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class GuavaMultiMapTest {
@Test
public void MultiMap() {
List<User> userList = new ArrayList<>();//假设是已经获取的用户信息集合
Multimap<Integer, User> multimap = HashMultimap.create();
for (User user : userList) {
multimap.put(user.getAge(),user);
}
}
}
class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
常用的方法
方法 | 描述 |
---|---|
get(K) | 集合形式返回键所对应的值 |
put(K, V) | 添加单个值 |
putAll(K, Iterable) | 添加多个值 |
remove(K, V) | 移除键对应值 |
removeAll(K) | 清除键对应的所有值,返回的集合包含所有之前映射到K的值,但修改这个集合就不会影响Multimap了。 |
replaceValues(K, Iterable) | 清除键对应的所有值,并重新把key关联到Iterable中的每个元素。返回的集合包含所有之前映射到K的值 |
asMap() |
Bimap
提供了key和value的双向关联的数据结构
1.假设我们需要通学生的姓名找到学号(这种普通的map可以实现)
@Test
public void logMapTest() {
Map<Integer, String> sMap = Maps.newHashMap();
sMap.put(1, "zs");
sMap.put(2, "li");
sMap.put(3, "ww");
//找到一号学生的名字
System.out.println(sMap.get(1));
}
2.还希望通过名字(假设名字唯一)找到工号
一般的做法是把map反转并保存
@Test
public void logMapTest() {
Map<Integer, String> sMap = new HashMap<>();
sMap.put(1, "zs");
sMap.put(2, "li");
sMap.put(3, "ww");
//找到一号学生的名字
System.out.println(sMap.get(1));
//反向保存
Map<String, Integer> inverseMap = new HashMap<>();
for(Map.Entry<Integer,String> entry: sMap.entrySet()) {
inverseMap.put(entry.getValue(), entry.getKey());
}
//找到'zs'学生的学号
System.out.println(inverseMap.get("zs"));
}
guava 的BiMap实现
@Test
public void testBiMap() {
BiMap biMap = HashBiMap.create();
biMap.put(1, "zs");
biMap.put(2, "li");
biMap.put(3, "ww");
//找到一号学生的名字
System.out.println(biMap.get(1));
//map键值对反向转换
BiMap inverseMap = biMap.inverse();
//找到'zs'学生的学号
System.out.println(inverseMap.get("zs"));
}
BiMap的实现种类
键–值实现 | 对应的BiMap实现 |
---|---|
HashMap | HashBiMap |
ImmutableMap | ImmutableBiMap |
EnumMap | EnumBiMap |
EnumMap | HashMap |
guava table
guava table 提供了多个索引的接口Table<R, C, V>
常见的常见包含: 保存一个班学生的成绩分数
@Test
public void testTable(){
//保存课程和分数
Table<String,String,Integer> table = HashBasedTable.create();
table.put("zs","java",100);
table.put("li","java",80);
table.put("ww","vue",95);
table.put("ww","java",50);
table.put("li","vue",60);
table.put("zs","vue",40);
//获取zs的java分数
System.out.println("zs的就java分数:"+table.get("zs","java"));
}
这里的2个键值其实就是行key®列key©
常用的方法和实现
方法 | 描述 |
---|---|
rowKeySet() | 得到所有的Rkey集合 |
rowMap() | 返回一个Map<R, Map<C, V>>的视图 |
row® | 用Map<C, V>返回给定”行”的所有列,对这个map进行的写操作也将写入Table中 |
cellSet() | 类似于Map.Entry但它是用行和列两个键区分的 |
columnKeySet() | 得到所有的列key |
columnMap() | 返回一个Map<C, Map<R, V>>的视图 |
row® | 用Map<C, V>返回给定”行”的所有列,对这个map进行的写操作也将写入Ta |
column© | 用Map<R, V>返回给定”列”的所有行,对这个map进行的写操作也将写入Table中 |
例子
@Test
public void testGuavaTable() {
//保存课程和分数
Table<String, String, Integer> table = HashBasedTable.create();
table.put("zs", "java", 100);
table.put("li", "java", 80);
table.put("ww", "vue", 95);
table.put("ww", "java", 50);
table.put("li", "vue", 60);
table.put("zs", "vue", 40);
//rowKeySet 获取的素有的学生姓名(行key))
Set<String> nameSet = table.rowKeySet();
System.out.println("班级所有学生的姓名: " + nameSet);
//columnKeySet 获取班级学生的考试的课程(列key)
Set<String> courseSet = table.columnKeySet();
System.out.println("班级学生考试的课程: " + courseSet);
//rowMap() 获取班级学生每个课程的成绩
Map<String, Map<String, Integer>> nameMap = table.rowMap();
System.out.println("班级学生每个课程的成绩: " + nameMap);
//columnMap() 获取班级课程每个学生的成绩
Map<String, Map<String, Integer>> courseMap = table.columnMap();
System.out.println("班级个课程每个学生的成绩: " + courseMap);
//row(r) 获取学生zs的所有课程成绩
Map<String, Integer> zsScoreMap = table.row("zs");
System.out.println("获取指定学生的所有课程的成绩: "+zsScoreMap);
//row(r) 获取学生zs的所有课程成绩
Map<String, Integer> coreMap = table.column("vue");
System.out.println("获取指定课程所有学生的成绩: "+coreMap);
}