Map接口

作者: Mcq | 来源:发表于2021-04-21 20:13 被阅读0次

    一个Map 是一个键值对对象。
    一个map不能包含重复的键:每个键最多可以映射到一个值,它对数学函数抽象进行了建模。

    Map接口基础操作

    put
    get
    remove
    containsKey
    containsValue
    size
    empty

    批量操作

    putAll
    clear

    集合视图

    keySet
    entrySet
    values

    Java平台包含三种Map实现:HashMap(无序)、TreeMap(按键的字母顺序顺序)和LinkedHashMap(原顺序),它们的行为和性能类似于HashSet、TreeSet和LinkedHashSet,如 The Set Interface一节所述。

    JDK8聚合操作收集Map的例子。
    在面向对象编程中,对现实世界的对象进行建模是一项日常操作。

    下面的例子按部门对员工进行分组:

    // Group employees by department
    Map<Department, List<Employee>> byDept = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment));
    

    按部门统计薪资:

    // Compute sum of salaries by department
    Map<Department, Integer> totalByDept = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment,
    Collectors.summingInt(Employee::getSalary)));
    

    按成绩及格与否,将学生分组:

    // Partition students into passing and failing
    Map<Boolean, List<Student>> passingFailing = students.stream()
    .collect(Collectors.partitioningBy(s -> s.getGrade()>= PASS_THRESHOLD)); 
    

    按城市进行分组:

    // Cascade Collectors 
    Map<String, Map<String, List<Person>>> peopleByStateAndCity
      = personStream.collect(Collectors.groupingBy(Person::getState,
      Collectors.groupingBy(Person::getCity)))
    

    Map接口基础操作

    Map的基本操作(put、get、containsKey、containsValue、size和isEmpty)与Hashtable中的对应操作完全相同。

    一个单词频次表的例子:

    public class Freq {
        public static void main(String[] args) {
            Map<String, Integer> m = new HashMap<String, Integer>();
    
            // Initialize frequency table from command line
            for (String a : args) {
                Integer freq = m.get(a);
                m.put(a, (freq == null) ? 1 : freq + 1);
            }
    
            System.out.println(m.size() + " distinct words:");
            System.out.println(m);
        }
    }
    

    与set和Listinterfaces类似,Map加强了对equals和hashCode方法,以便比较两个Map对象的逻辑相等性,而不必考虑它们的实现类型。两个Map的键值都相等,则两者相等。

    通常所有通用Map实现的构造函数接受Map对象并初始化新Map,相当于复制一个相同的Map。这个标准Map转换构造函数完全类似于标准Collection 构造函数。

    Map<K, V> copy = new HashMap<K, V>(m);
    

    Map接口批量接口

    clear 删除所有元素
    putAll 类似于Collection的addAll,与构造函数一起使用可实现按默认值创建Map:

    static <K, V> Map<K, V> newAttributeMap(Map<K, V>defaults, Map<K, V> overrides) {
        Map<K, V> result = new HashMap<K, V>(defaults);
        result.putAll(overrides);
        return result;
    }
    

    集合视图

    Collection views 方法可以把Map视为Collection:

    • keySet — 返回Map的key的Set。
    • values — 返回Map的值的Collection。
    • entrySet — 返回Map键值对构成的Set,类型为Map.Entry。
    for (KeyType key : m.keySet())
        System.out.println(key);
    

    iterator

    // Filter a map based on some 
    // property of its keys.
    for (Iterator<Type> it = m.keySet().iterator(); it.hasNext(); )
        if (it.next().isBogus())
            it.remove();
    

    迭代键值对

    for (Map.Entry<KeyType, ValType> e : m.entrySet())
        System.out.println(e.getKey() + ": " + e.getValue());
    

    最初,许多人担心这些习惯用法可能很慢,因为每次调用集合视图操作时,映射都必须创建一个新的Collection 实例。大可放心:每次请求给定的集合视图时,Map总是返回相同的对象,这正是java中所有Map实现在java.util中做的。

    三种Collection 视图中,Iterator的 remove 和 entrySet视图的Map.Entry's setValue 是Map迭代过程中的安全操作,其他操作行为可能是不明确的。

    Collection视图支持移除操作, remove, removeAll, retainAll和 clear 。
    在任何情况下,Collection视图都不支持添加元素,因为Map的put和putAll方法已经提供了相同的功能。

    Collection视图的奇妙用法:映射代数

    判断一个Map是否为另一个Map的子集,即包含所有键值对:

    if (m1.entrySet().containsAll(m2.entrySet())) {
        ...
    }
    

    判断两个Map是否相同:

    if (m1.keySet().equals(m2.keySet())) {
        ...
    }
    

    假设你有一个Map和两个分别表示必须属性和允许属性的Set,判断Map是否符合限制:

    static <K, V> boolean validate(Map<K, V> attrMap, Set<K> requiredAttrs, Set<K>permittedAttrs) {
        boolean valid = true;
        Set<K> attrs = attrMap.keySet();
    
        if (! attrs.containsAll(requiredAttrs)) {
            Set<K> missing = new HashSet<K>(requiredAttrs);
            missing.removeAll(attrs);
            System.out.println("Missing attributes: " + missing);
            valid = false;
        }
        if (! permittedAttrs.containsAll(attrs)) {
            Set<K> illegal = new HashSet<K>(attrs);
            illegal.removeAll(permittedAttrs);
            System.out.println("Illegal attributes: " + illegal);
            valid = false;
        }
        return valid;
    }
    

    求两个Map公共的key:

    Set<KeyType>commonKeys = new HashSet<KeyType>(m1.keySet());
    commonKeys.retainAll(m2.keySet());
    

    之前的所有操作都没有改变原Map结构的,但有操作会改变原Map,比如,删除一个Map中它和另一个Map的相同键值对:

    m1.entrySet().removeAll(m2.entrySet());
    

    比如,删除一个Map中它和另一个Map的相同键:

    m1.keySet().removeAll(m2.keySet());
    

    假设有一个Map,映射员工和管理者的关系,找出没有管理者的员工:

    Set<Employee> individualContributors = new HashSet<Employee>(managers.keySet());
    individualContributors.removeAll(managers.values());
    

    开除Simon的所有下属:

    Employee simon = ... ;
    managers.values().removeAll(Collections.singleton(simon));
    

    所属管理者不再为公司工作的员工:

    Map<Employee, Employee> m = new HashMap<Employee, Employee>(managers);
    m.values().removeAll(managers.keySet());
    Set<Employee> slackers = m.keySet();
    

    Multimaps多重映射

    multimap类似于Map,但它可以将每个键映射到多个值。

    multimap类似于Map,但它可以将每个键映射到多个值。Java Collections框架没有包含用于multimap的接口,因为它们并不经常使用。把值类型为List的Map用作multimap,是一件相当简单的事情。下一个代码示例将演示这种技术,该代码示例读取每行包含一个单词的单词列表(全部小写),并打印出满足大小标准的所有字谜组。字谜组是一堆单词,它们都包含完全相同的字母,但顺序不同。
    该程序在命令行上接受两个参数:(1)字典文件的名称和(2)要打印的字谜组的最小大小。包含少于指定最小字数的字谜组不会被打印。

    有一个查找字谜组的标准技巧:对于字典中的每个单词,将单词中的字母按字母顺序排列(即将单词的字母按字母顺序重新排列),并将一个条目放入multimap中,将按字母顺序排列的单词映射到原始单词。例如,bad这个词会导致将abd映射为bad的条目被放入multimap中。稍作思考,你就会发现,所有的字词,任何给定的关键图都可以组成一个字词组合。遍历multimap中的键,打印出满足大小约束的每个字谜组,是一件很简单的事情。

    
    public class Anagrams {
        public static void main(String[] args) {
            int minGroupSize = Integer.parseInt(args[1]);
    
            // Read words from file and put into a simulated multimap
            Map<String, List<String>> m = new HashMap<String, List<String>>();
    
            try {
                Scanner s = new Scanner(new File(args[0]));
                while (s.hasNext()) {
                    String word = s.next();
                    String alpha = alphabetize(word);
                    List<String> l = m.get(alpha);
                    if (l == null)
                        m.put(alpha, l=new ArrayList<String>());
                    l.add(word);
                }
            } catch (IOException e) {
                System.err.println(e);
                System.exit(1);
            }
    
            // Print all permutation groups above size threshold
            for (List<String> l : m.values())
                if (l.size() >= minGroupSize)
                    System.out.println(l.size() + ": " + l);
        }
    
        private static String alphabetize(String s) {
            char[] a = s.toCharArray();
            Arrays.sort(a);
            return new String(a);
        }
    }
    

    相关文章

      网友评论

          本文标题:Map接口

          本文链接:https://www.haomeiwen.com/subject/caamfltx.html