`

可以存储相同key的map——Multimap

    博客分类:
  • java
阅读更多

总结:

  1. Multimap允许key重复(Map是不允许的,若在装入Map时,出现相同key,后者会将前者覆盖)。

  2. 判断两个集合是否存在交集:!Collections.disjoint(list1, list2);

      或!CollectionUtils.containsAny(list1,list2);

  3. 求集合的包含和所属关系:b.containsAll(a)或CollectionUtils.containsAll(b, a)

  4. key value都相同[键值对相同,相同的key,相同的value],使用HashMultimap会只

      保留一份记录,因为它是继承自AbstractSetMultimap这样的Set类实现的,可以使用

      ArrayListMultimap等继承自AbstractListMultimap的类来实例化对象。

 

前不久在这篇 使用 Google Guava 美化你的 Java 代码:1~4 中的 “一个集合统治一切 – Multimap” 部分提到过这货,不过当时那篇文章受限于篇幅,例子举的不够详尽,估计很多同学看了还是云里雾里,一头雾水。

说个具体的应用场景吧:

比如现在我有一份日志记录,每条记录的内容是一个 url 对应一个访客的 userid,我现在想得到 每个 url 对应的 pv、uv 数据,你会怎么做?

普通青年一般这么想的:用 url 做 key,userid 作为对应 list 的内容:

1
Map<String,List<MyClass>> myClassListMap = new HashMap<String,List<MyClass>>()

然后你需要检查key是否存在,否则创建一个,最后代码成为这个样子: 

1
2
3
4
5
6
7
8
void putMyObject(String key, Object value) {
    List<Object> myClassList = myClassListMap.get(key);
    if(myClassList == null) {
        myClassList = new ArrayList<object>();
        myClassListMap.put(key,myClassList);
    }
    myClassList.add(value);
}

如果你希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么需要更多的代码。 

看到这里不禁感叹一句:这特么都什么玩意啊。。。

恩,懒人总有懒人的办法,习惯脚本语言的我,很难忍受 java 的这种臃肿的代码了,下面看看用之前提到的 Guava MultiMap 怎么优雅的解决这个问题。

 

1
Multimap<String,Object> myMultimap = ArrayListMultimap.create();

这里需要注意,所有的guava的集合都有create()方法,这个好处就是比较简单,你不用重复泛型信息了。  

好了,开始使用Multimap了:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.test;
 
import java.util.Collection;
 
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
 
public class MutliMapTest {
    public static void main(String... args) {
        Multimap<String, String> myMultimap = ArrayListMultimap.create();
 
        // Adding some key/value
        myMultimap.put("Fruits", "Bannana");
        myMultimap.put("Fruits", "Apple");
        myMultimap.put("Fruits", "Pear");
        myMultimap.put("Fruits", "Pear");
        myMultimap.put("Vegetables", "Carrot");
 
        // Getting the size
        int size = myMultimap.size();
        System.out.println(size); // 5
 
        // Getting values
        Collection<String> fruits = myMultimap.get("Fruits");
        System.out.println(fruits); //  [Bannana, Apple, Pear, Pear]
        System.out.println(ImmutableSet.copyOf(fruits));// [Bannana, Apple, Pear] 这里有个去重的做法
        // Set<Foo> set = Sets.newHashSet(list);
        // Set<Foo> foo = new HashSet<Foo>(myList);
 
        Collection<String> vegetables = myMultimap.get("Vegetables");
        System.out.println(vegetables); // [Carrot]
 
        // Iterating over entire Mutlimap
        for (String value : myMultimap.values()) {
            System.out.println(value);
        }
 
        // Removing a single value
        myMultimap.remove("Fruits", "Pear");
        System.out.println(myMultimap.get("Fruits")); // [Bannana, Apple, Pear]
 
        // Remove all values for a key
        myMultimap.removeAll("Fruits");
        System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
    }
}

这里有一点你可能会疑惑,就是为何get方法返回的是一个collection而不是list,这是因为前者会更加有用。如果你需要基于multimap直接操作list或者set,那么可以使用在定义类型的时候使用子类名称:ListMultimap,SetMultimap和SortedSetMultimap。例如: 

 

1
2
3
ListMutlimap<String,String> myMutlimap = ArrayListMultimap.create();
 
List<string> myValues = myMutlimap.get("myKey");  // Returns a List, not a Collection.

好了,基本就是这样,你可以参考API获取更多信息:

http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/index.html

PS: 下面再补充另一个问题:如何判断两个集合是否存在交集?

(1)普通写法:双层 for 循环遍历两个集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           break;
           //also do something
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

(2)JDK 自带的集合方法:disjoint

1
!Collections.disjoint(list1, list2);

(3) 使用第三方库: Apache Commons CollectionUtils

http://commons.apache.org/proper/commons-collections/javadocs/api-release/index.html

1
2
3
4
5
6
7
if(CollectionUtils.containsAny(list1,list2) 
    //do whatever
else{
     //do other thing
}

(4)不太高效的,但是简洁可用的变通方法:retainAll

1
2
if (!new HashSet<T>(list1).retainAll(list2).isEmpty())
    // at least one element is shared

(5)顺便说下如何求集合的包含、所属关系:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
 
    public static void main(String[] args) throws IOException {
        Set a = new HashSet() {
            {
                add(1);
                add(2);
            }
        };
 
        Set b = new HashSet() {
            {
                add(2);
                add(3);
                add(1);
            }
        };
 
        System.out.println(b.containsAll(a));
        System.out.println(CollectionUtils.containsAll(b, a));
 
    }
 
}
 
 

 来源: <http://my.oschina.net/leejun2005/blog/179645>

分享到:
评论

相关推荐

    C++模板(vector、map、multimap、set、multiset)

    这意味着相同键值可以对应多个值。这在需要存储多对一映射关系时非常有用。 4. **set**: `std::set` 也是关联容器,它包含唯一的元素,元素之间按照特定的顺序排列。`set` 通常用于存储无序的唯一元素集合,其底层...

    map/multimap属于**关联式容器**,底层结构是用二叉树实现

    `map`提供了一种键值对(key-value pair)的存储方式,其中每个元素都包含一个键和一个与该键相关联的值。键在`map`中必须是唯一的,这意味着不能有重复的键值。`map`按照键的排序来组织元素,通常默认的排序规则是...

    前K个高频单词(map+multimap)1

    这个问题可以通过使用C++中的`map`和`multimap`数据结构来解决。 首先,我们需要理解`map`和`multimap`的基本概念。`map`是一个关联容器,它包含唯一键值对,这里的键是单词,值是对应的出现次数。`map`内部默认...

    c++ vs2019 cpp20规范的STL库的map与multimap源码分析

    c++ vs2019 cpp20规范的STL库的map与multimap源码分析

    C++ STL(vector+multimap容器)案例

    通过multimap进行信息的插入 key(部门编号) value(员工) 分部门显示员工信息 实现步骤: 创建10名员工,放到vector中 遍历vector容器,取出每个员工,进行随机分组 分组后,将员工部门编号作为key,具体员工作为...

    好友列表(multimap实现)

    与`std::map`不同,`std::multimap`允许有多个具有相同键的元素。在“好友列表”这个场景中,我们可以用`std::multimap`来表示用户与其朋友的关系,因为一个用户可能有多个朋友。 在`multimap`中,每个元素都是一个...

    c++中map的基本用法和嵌套用法实例分析

    `,还可以使用`make_pair`简化写法:`my_Map.insert(make_pair, int&gt;("key", 4));` 4. **查找和修改数据** - 直接通过索引访问并修改:`int i = my_Map[1]; my_Map[1] = i;` - 使用迭代器查找并修改:`MY_MAP::...

    STL中map用法详解

    其中,`map`容器是STL中用于存储键值对(key-value pairs)的数据结构,适用于关联式查找和操作。本文将深入解析STL中的`map`用法,帮助你理解其基本概念、操作和应用场景。 1. **map的基本概念** `map`是一个关联...

    STL容器multimap的使用

    在STL容器中,`multimap`是一种关联容器,它允许元素以键值对的形式存储,并且一个键可以对应多个值。与`map`不同的是,`map`保证了键的唯一性,而`multimap`则允许重复的键。 在`multimap`中,每个元素都是一个...

    map_code.rar_code_linux map_map

    3. **Multimap数据结构**:与map类似,但multimap允许相同的键有多个不同的值。这在需要根据一个键存储多个相关值时非常有用。 4. **DWORD类型**:在Windows API中,DWORD是一个无符号双字节整型,通常表示16位或32...

    利用快速排序及multimap统计文件频率靠前的单词

    本程序用c++标准库中的快速排序算法以及容器map和multimap实现了对文件中出现频率靠前的单词进行了统计,至于文件大小取决于你机器所剩的内存数,如果文件数据时海量的(上亿)则本程序可能不适合,需要按照海量数据...

    C++ map详解

    C++中的`map`是一个关联容器,它存储键值对(key-value pairs),其中每个键都是唯一的。`map`在内部实现为红黑树(Red-Black Tree),保证了其插入、查找和删除操作的时间复杂度为O(log n)。在C++标准库中,`map`...

    multimap实现tlv

    标题中的“multimap实现tlv”指的是在C++编程中使用`std::multimap`容器来实现一种特定的数据结构——TLV(Tag-Length-Value)。TLV是一种常见于网络协议和数据序列化中的数据表示方式,它将数据分为三个部分:标签...

    map容器实现方法

    在C++标准库中,`map`容器是一个关联容器,它提供了一种通过键(key)来访问元素的方式。`map`容器中的每个元素都包含一个键值对,键是唯一的,而对应的值可以重复。这里我们将深入探讨`map`容器的实现方法,包括其...

    stl中map用法详解

    与`map`不同,`multimap`允许相同的键存在,其行为类似于键值对的集合。 ### 结论 STL中的`map`是一个强大的数据结构,它为键值对的存储提供了高效且便捷的接口。熟练掌握`map`的用法,能极大地提升C++编程的效率...

    stl_map.rar_STL mapping

    在STL中,`map`和`multimap`是两种非常重要的关联容器,它们用于存储键值对数据,非常适合进行快速查找和访问。 `map`容器: 1. **定义**:`map`是一个关联容器,它包含唯一键值对(key-value pairs)。每个键值对...

    AVL_Tree实现STL中的map, set, multimap和multiset

    用AVL-tree数据结构作为底层机制,以STL底层空间配置器和iterator_traits编程技法实作出一个独立的关联式容器(map, set, multimap, multiset),并对外提供接口实现和STL完全兼容的容器。

    每天学点C++(C++实例教程:教程+源码)map容器.zip

    在`multimap`中,相同的键可以对应多个值。 通过这个实例教程,你可以学习如何在实际项目中有效地使用`map`容器,理解其工作原理,并掌握相关操作。记得动手实践,理论结合实践是学习编程的最佳方式。

Global site tag (gtag.js) - Google Analytics