黑马程序员技术交流社区

标题: 考题举一反五秒变大神:如何去除map所有重复值(附方法及详解 [打印本页]

作者: 378657357    时间: 2016-9-18 00:44
标题: 考题举一反五秒变大神:如何去除map所有重复值(附方法及详解
本帖最后由 378657357 于 2016-9-26 01:44 编辑

package com.heima.test;
import java.util.HashMap;
/*
去除双列集合中所有重复的值
附5种方法代码、思路(详细注释)
*/
public class Ex_Text1 {
        public static void main(String[] args) throws Exception {
                HashMap<Integer,String> hm = new HashMap<>();
                //添加了20个测试数据,有相邻重复的,有间隔重复的,确保准确性,觉得不够欢迎继续添加测试
                hm.put(1, "11");
                hm.put(2, "11");
                hm.put(3, "11");
                hm.put(4, "22");
                hm.put(5, "22");
                hm.put(6, "33");
                hm.put(7, "11");
                hm.put(8, "22");
                hm.put(9, "22");
                hm.put(10, "44");
                hm.put(11, "55");
                hm.put(12, "77");
                hm.put(13, "33");
                hm.put(14, "44");
                hm.put(15, "44");
                hm.put(16, "66");
                hm.put(17, "88");
                hm.put(18, "99");
                hm.put(19, "55");
                hm.put(20, "11");        
                //第一种是用集合交换的思想来完全去重的
                System.out.println(quchong1(hm));
                //后面的四种总体思想都是将集合的值全部汇总到一个字符串中,再对其进行操作、判断是否重复的操作
                        //字符串indexOf和lastIndexOf查找判断是否重复
                        System.out.println(quchong2(hm));
                        //用str.indexOf(String str);        str.indexOf(String str, index fromIndex);方法判断处理
                        System.out.println(quchong3(hm));
                        //用str.substring(beginIndex);        str.contains(String str);        str.indexOf(String str);方法判断处理        
                        System.out.println(quchong4(hm));
                        //字符串数组选择排序比较原理,发现相等的就一键清理
                        System.out.println(quchong5(hm));
        }
        //去除双列集合所有重复值的方法1
        private static HashMap<Integer, String> quchong1(HashMap<Integer, String> hm) {
                //传入要完全去重的集合hm,创建完全去重的集合hhmm,以及过渡集合hm1
                //过渡集合hm1泛型和原集合hm不同,因为hm1的键要装的是hm的值,hm1的值就是记录hm的值的出现的次数(有点绕,但是需要理解)
                HashMap<Integer, String> hhmm = new HashMap<>();
                HashMap<String, Integer> hm1 = new HashMap<>();
                for (Integer key : hm.keySet()) {
                        String xinkey = hm.get(key);
                        hm1.put(xinkey, hm1.containsKey(xinkey) ? hm1.get(xinkey)+1 : 1);
                }
                //将原集合进行遍历,如果有过渡集合中的键,且其对应的值为1(只出现了1次,即代表不重复的意思),就将他添加到新集合hhmm中输出
                for (Integer key : hm.keySet()) {
                        if (hm1.containsKey(hm.get(key)) && hm1.get(hm.get(key)) == 1) {
                                hhmm.put(key, hm.get(key));
                        }
                }
                return hhmm;
        }
        
        //去除双列集合所有重复值的方法2
        private static HashMap<Integer, String> quchong2(HashMap<Integer, String> hm) {
                HashMap<Integer, String> hhmm = new HashMap<Integer, String>();
                //遍历双列集合,将需要去重的集合的值全部汇集到字符串str中,值与值之间用空格隔开
                String str = "";
                for (Integer key : hm.keySet()) {
                        str = str + hm.get(key) + " ";
                }
                //System.out.println(str);           //要查看汇总完后的字符串str,解封此注释
               
                //将字符串用空格切开,其实就是得到了原集合的各个值的String形式,下面就对其进行去重判断操作
                //思路:  比如这个字符串是11 22 33 22 22 44
                //如果不重复,那么indexOf和lastIndexOf拿到的索引肯定相同(一个是从前往后找匹配的索引,一个是从后往前找匹配的索引)
                //如果重复了,那么拿到的索引肯定不同,例如str.indexOf("22")拿到的是3,而str.lastIndexOf("22")是12
                String[] arr = str.split(" ");
                for (int i = 0; i < arr.length; i++) {
                        if (str.indexOf(arr) != str.lastIndexOf(arr)) {
                                //只要重复了,就把这个重复的值意见替换成""(相当于清除掉了)
                                str = str.replaceAll(arr, "");
                        }
                }
                //System.out.println(str);           //要查看去重完后的字符串str,解封此注释,字符串中有空格,但那都不是事儿
                //将去重后的字符串里的值和原集合值比对(都要转成字符串形式),如果原集合中有这个字符串中的值,那就是不重复的,再添加到新集合输出
                for (Integer key : hm.keySet()) {
                        if (str.contains(hm.get(key).toString())) {
                                hhmm.put(key, hm.get(key));
                        }
                }        
                return hhmm;
        }
               
        //去除双列集合所有重复值的方法3
        private static HashMap<Integer, String> quchong3(HashMap<Integer,String> hm) {
                HashMap<Integer, String> hhmm = new HashMap<Integer, String>();
                //这里步骤同方法1,用一个字符串接收原集合的所有的值,中间用空格隔开
                String str = "";
                for (Integer key : hm.keySet()) {
                        str = str + hm.get(key) + " ";
                }
/*                要用到的方法        
                 indexOf方法1:str.indexOf("需要搜索并返回其对应索引的对象");
                indexOf方法2:str.indexOf("对象(详解见上行)", "从第几个索引开始往后找这个对象");         
                原理:如果这个对象只出现了一次,那么用indexOf方法2的话,在这个对象第一次出现的索引之后用再开始找,
                那么返回的就是-1(如果不重复就返回-1,如果有重复的,indexOf方法2就会返回这个重复值第二次出现的索引位置)
                字符串索引去重法,从第一个值后的索引找,如果他是唯一的,那就得返回-1.
                不是-1,那就是有重复的,一键清理
                思路举例:  比如字符串是11 22 33 44 33 22 11 55 66
                我用indexOf方法1:str.indexOf("22");  给我返回索引3
                我再以这个索引为基础加上这个对象的长度,作为起始索引,调用indexOf方法2:indexOf方法2:str.indexOf("22",这个对象的长度+他第一次出现的索引);         
                 因为22是重复的,所以调用方法2,他又给我返回索引15,我就这么调用方法1和2各一次就行,重复的就一键删除,不要管他出现多少次                */
                String[] arr = str.split(" ");
                for (int i = 0; i < arr.length; i++) {
                        if (str.indexOf(arr, str.indexOf(arr)+arr.length()) != -1) {
                                str = str.replaceAll(arr, "");
                        }
                }
                //将去重后的字符串里的值和原集合值比对,如果原集合中有这个字符串中的值,那就是不重复的,再添加到新集合输出
                for (Integer key : hm.keySet()) {
                        if (str.contains(hm.get(key))) {
                                hhmm.put(key, hm.get(key));
                        }
                }
                return hhmm;
        }
        
        //去除双列集合所有重复值的方法4:用str.substring(beginIndex);        str.contains(String str);        str.indexOf(String str);方法判断处理
        private static HashMap<Integer, String> quchong4(HashMap<Integer, String> hm) {
                HashMap<Integer, String> hhmm = new HashMap<Integer, String>();
                //遍历双列集合,将需要去重的集合的值全部汇集到字符串str中,值与值之间用空格隔开
                String str = "";
                for (Integer key : hm.keySet()) {
                        str = str + hm.get(key) + " ";
                }
                //方法思路,如果重复了,那么我下面这句判断语句肯定就是true,然后我就进行一键删除所有重复的
                //原理:最外层方法str.substring(截取第一个需要判断是否重复的值arr的索引后面)再.contains(arr)是否还包含,如果还包含,那么肯定是重复的
                String[] arr = str.split(" ");
                for (int i = 0; i < arr.length; i++) {
                        //substring括号里的意思就是需要判断是否重复的值arr第一次出现的地方的索引(记住索引要加上arr其长度)开始
                        if (str.substring(str.indexOf(arr)+arr.length()).contains(arr)) {
                                str = str.replaceAll(arr, "");
                        }
                }
                //System.out.println(str);           //要查看去重完后的字符串str,解封此注释,字符串中有空格,但那都不是事儿
                //将去重后的字符串里的值和原集合值比对(都要转成字符串形式),如果原集合中有这个字符串中的值,那就是不重复的,再添加到新集合输出
                for (Integer key : hm.keySet()) {
                        if (str.contains(hm.get(key).toString())) {
                                hhmm.put(key, hm.get(key));
                        }
                }        
                return hhmm;
        }
        
        //去除双列集合所有重复值的方法5:字符串数组选择排序原理(冒泡排序不行)比较,发现相等的就一键清理
        //(和这个选择排序原理类似,他是充分判断大小,符合就交换,我的是充分判断大小,如果相等(重复),那么我就删除原字符串中重复的,不是删除数组)
                private static HashMap<Integer, String> quchong5(HashMap<Integer, String> hm) {
                        HashMap<Integer, String> hhmm = new HashMap<Integer, String>();
                        //遍历双列集合,将需要去重的集合的值全部汇集到字符串str中,值与值之间用空格隔开
                        String str = "";
                        for (Integer key : hm.keySet()) {
                                str = str + hm.get(key) + " ";
                        }
                        //选择排序原理,我拿出数组中第一个(原集合值的String形式)分别与后面的去比较,发现有重复的,我就删除,然后继续第二个第二三个直至循环完充分比较
                        String[] arr = str.split(" ");
                        for (int i = 0; i < arr.length-1; i++) {
                                for (int j = 1+i; j < arr.length; j++) {
                                        if (arr.equals(arr[j])) {
                                                str = str.replaceAll(arr[j], "");
                                        }
                                }        
                        }
                        //将去重后的字符串里的值和原集合值比对(都要转成字符串形式),如果原集合中有这个字符串中的值,那就是不重复的,再添加到新集合输出
                        for (Integer key : hm.keySet()) {
                                if (str.contains(hm.get(key).toString())) {
                                        hhmm.put(key, hm.get(key));
                                }
                        }        
                        return hhmm;
                }
}



作者: 378657357    时间: 2016-9-18 00:47
自顶沙发
作者: 风轻云淡139    时间: 2016-9-18 00:50
好多代码啊~~~~
作者: 378657357    时间: 2016-9-18 01:43
风轻云淡139 发表于 2016-9-18 00:50
好多代码啊~~~~

解决问题就要举一反三~~~
我这里是举一反五,代码当然会有点多...
第一种方法是利用双列集合的特性交换交叉完全去重
第二到第五种方法都是利用字符串配合正则表达式完全去重的思想,先把原map集合的值遍历全部添加到一个字符串中(利用空格隔开以区分),然后利用第二到第四种方法判断字符串中有没有重复的,有就用正则表达式删除重复的(replaceAll把符合的重复的子字符串全部替换成空串""达到去重),然后拿这个去重之后的字符串去遍历原map集合比对,如果去重后的字符串里包含map中的值,那么就不是重复的,添加到一个新map集合中.以此达到完全去重的效果.
(因为我对字符串进行处理切割都是利用原集合键里没有的符号空格,所以当原map集合值没有空格就行)

这是一个点招面试题,从朋友那边听来的
方法虽多,掌握第一种,就对集合有一个比较熟悉的了解认识和运用了.
如果能理解第二到四种字符串去重所利用的操作方法和思想,你的String相关操作绝对是没有什么问题的!


作者: 为了王者上JAVA    时间: 2016-9-28 01:13
方法一用集合好保险代码思路也很清晰啊
后面几个感觉有些类似啊,就是变成了字符串去重?
作者: kansyoukyou    时间: 2016-9-28 10:37
好多,看不过来~··
作者: 378657357    时间: 2016-9-28 10:55
kansyoukyou 发表于 2016-9-28 10:37
好多,看不过来~··

复制粘贴到eclipse里头一个一个方法分解看,我这里是五种,你要是能一下子都看懂那还怎么玩...




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2