黑马程序员技术交流社区

标题: 关于数组比较器Comparator 求解答 [打印本页]

作者: 冯越    时间: 2012-5-21 16:43
标题: 关于数组比较器Comparator 求解答
本帖最后由 冯越 于 2012-5-21 17:35 编辑

今天在黑马论坛上帮别人解决问题,虽然问题得以解决了,但却不是我心中最完美的方法。问题是这样的:http://bbs.itheima.com/thread-15093-1-1.html
一楼是我的解答,但我当时我的原始的想法是这样的:
public class Birthday {
        
        public static void birthday(String[] birthdays) {
                Map<String, Integer> map = new TreeMap<String, Integer>();
                for(String birthday : birthdays) {
                        if(map.get(birthday) == null) {
                                map.put(birthday, 1);
                        } else {
                                int value = map.get(birthday) + 1;
                                map.put(birthday, value);
                        }
                }        
                System.out.println(map);        
                Set<Map.Entry<String, Integer>> set = map.entrySet();        
                Map.Entry<String, Integer>[] entrys = (Map.Entry<String, Integer>[])set.toArray();
                Arrays.sort(entrys,new Comparator(){    //这个地方报错了 编译器报了参数类型不匹配错误 我十分不解 望高手给予解答
                        public int compare(Object o1, Object o2) {               
                                Map.Entry<String, Integer> m1 = (Map.Entry<String, Integer>) o1;
                                Map.Entry<String, Integer> m2 = (Map.Entry<String, Integer>) o2;
                                if(m1.getValue() > m2.getValue()) {
                                        return -1;
                                } else if(m1.getValue() < m2.getValue()) {
                                        return 1;
                                } else  {
                                        return 0;
                                }                        
                        }        
                });
                System.out.println("日期重复次数从多到少排列为:")         
                For(Map.Entry<String, Integer> entry : entrys) {        //这里把上面经过重新排列的数组ForEach输出
                       System.out.println(entry.getKey() + "---------------->" + entry.getValue());
                }
               
        }
               
        public static void main(String[] args) {
                birthday(args);  //这里我在运行参数里 随便的输入了一些日期 比如 0404 0512什么的
        }
}

希望高手能帮我解答 在我给数组加比较器的那一步 为何编译器会报错呢???

11.jpg (173.9 KB, 下载次数: 18)

11.jpg

作者: 云惟桉    时间: 2012-5-21 16:50
本帖最后由 云惟桉 于 2012-5-21 18:46 编辑

楼主需要注意的是:Comparator是一个接口,不能直接new对象的。
需要做的是自己写一个比较器类,实现Comparator接口,覆盖接口里的compare方法。
并且需要注意的是,compare方法返回的是整型值int,详细可以参考API。

所以,楼主的静态函数使用是没错的,只是应该自己再写一个比较器,按照自定义的方式比较。
参数是自定义的比较器对象。这样就没问题了。

版主我知错了~~~  已经在下面楼层下跪悔错了,求原谅~
作者: 8161776    时间: 2012-5-21 17:13
本帖最后由 杨尧 于 2012-5-21 17:14 编辑
  1. public class Birthday {
  2.         
  3.         public static void birthday(String[] birthdays) {
  4.                 Map<String, Integer> map = new TreeMap<String, Integer>();
  5.                 for(String birthday : birthdays) {
  6.                         if(map.get(birthday) == null) {
  7.                                 map.put(birthday, 1);
  8.                         } else {
  9.                                 int value = map.get(birthday) + 1;
  10.                                 map.put(birthday, value);
  11.                         }
  12.                 }        
  13.                 System.out.println(map);        
  14.                 Set<Map.Entry<String, Integer>> set = map.entrySet();        
  15.                 Map.Entry<String, Integer>[] entrys = (Map.Entry<String, Integer>[])set.toArray();
  16.                 Arrays.sort(entrys,new Comparator(){    //这个地方报错了 编译器报了参数类型不匹配错误 我十分不解 望高手给予解答



  17. //上面报错的原因是你把下面的方法名字写错了,应该是compare 你写成compara了我试过了,改成compare就可以了
  18. //Comparator是一个接口,你在上面直接new了他,你就就必须在下面实现他的compare方法,这样才是匿名内部类



  19.                         public int compara(Object o1, Object o2) {               
  20.                                 Map.Entry<String, Integer> m1 = (Map.Entry<String, Integer>) o1;
  21.                                 Map.Entry<String, Integer> m2 = (Map.Entry<String, Integer>) o2;
  22.                                 if(m1.getValue() > m2.getValue()) {
  23.                                         return -1;
  24.                                 } else if(m1.getValue() < m2.getValue()) {
  25.                                         return 1;
  26.                                 } else  {
  27.                                         return 0;
  28.                                 }                        
  29.                         }        
  30.                 });
  31.                 System.out.println("日期重复次数从多到少排列为:")         
  32.                 For(Map.Entry<String, Integer> entry : entrys) {        //这里把上面经过重新排列的数组ForEach输出
  33.                        System.out.println(entry.getKey() + "---------------->" + entry.getValue());
  34.                 }
  35.                
  36.         }
  37.                
  38.         public static void main(String[] args) {
  39.                 birthday(args);  //这里我在运行参数里 随便的输入了一些日期 比如 0404 0512什么的
  40.         }
  41. }
复制代码

作者: 冯越    时间: 2012-5-21 17:14
云惟桉 发表于 2012-5-21 16:50
楼主需要注意的是:Comparator是一个接口,不能直接new对象的。
需要做的是自己写一个比较器类,实现Compar ...

你没看出来我写的是一个匿名类吗? 你说的并不是问题的所在
作者: 冯越    时间: 2012-5-21 17:31
杨尧 发表于 2012-5-21 17:13

改了,还是错了。我上传了张图片 你看看吧
作者: 云惟桉    时间: 2012-5-21 18:27
本帖最后由 云惟桉 于 2012-5-21 18:30 编辑
  1. package cn.yun.test;
  2. import java.util.*;
  3. public class test7 {
  4.    
  5.     public static void birthday(String[] birthdays) {
  6.             Map<String, Integer> map = new TreeMap<String, Integer>();
  7.             for(String birthday : birthdays) {
  8.                     if(map.get(birthday) == null) {
  9.                             map.put(birthday, 1);
  10.                     } else {
  11.                             int value = map.get(birthday) + 1;
  12.                             map.put(birthday, value);
  13.                     }
  14.             }        
  15.             System.out.println(map);        
  16.             Set<Map.Entry<String, Integer>> set = map.entrySet();        
  17.                         List<Map.Entry<String, Integer>> entrys = new ArrayList<Map.Entry<String,Integer>>();
  18.                         
  19.                         for(Iterator<Map.Entry<String, Integer>> it = set.iterator();it.hasNext();){
  20.                                 entrys.add(it.next());
  21.                         }        
  22.                         
  23.             Collections.sort(entrys,new Comparator<Map.Entry<String, Integer>>(){    //这个地方报错了 编译器报了参数类型不匹配错误 我十分不解 望高手给予解答
  24.                     public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {               
  25.                             Map.Entry<String, Integer> m1 = o1;
  26.                             Map.Entry<String, Integer> m2 = o2;
  27.                             if(m1.getValue() > m2.getValue()) {
  28.                                     return -1;
  29.                             } else if(m1.getValue() < m2.getValue()) {
  30.                                     return 1;
  31.                             } else  {
  32.                                     return 0;
  33.                             }                        
  34.                     }        
  35.             });
  36.             
  37.             System.out.println("日期重复次数从多到少排列为:");         
  38.             for(Map.Entry<String, Integer> entry : entrys) {        //这里把上面经过重新排列的数组ForEach输出
  39.                    System.out.println(entry.getKey() + "---------------->" + entry.getValue());
  40.             }
  41.             
  42.     }
  43.             
  44.     public static void main(String[] args) {
  45.             birthday(args);  //这里我在运行参数里 随便的输入了一些日期 比如 0404 0512什么的
  46.     }
  47. }
复制代码
不好意思刚我看错了,用手机就是容易看漏代码不好意思噢。。
楼主的报错我没遇到,就是楼主说的【参数不匹配】错误我没遇到。
不过按照楼主的代码输入了,运行时会报【类型转换异常】。
根源是泛型的问题:

Map.Entry<String, Integer>[] entrys = (Map.Entry<String, Integer>[])set.toArray();
以上这一句使用了参数化类型的数组,因为有转换操作,是运行时异常,编译时没报错。
但是,java的语法规定,是不可以定义参数化类型数组的。

比如说:Pair<String>[] table =new Pair<String>[10];   //ERROR
如果楼主想进一步了解原理,可以上网查询资料,讲得绝对比我清楚的。

然后这时就不能用Arrays的sort方法了,但是需要啊排序可以使用Collections的sort方法,将一个List进行排序
因此就需要以下操作:
Set<Map.Entry<String, Integer>> set = map.entrySet();        
List<Map.Entry<String, Integer>> entrys = new ArrayList<Map.Entry<String,Integer>>();
                        
for(Iterator<Map.Entry<String, Integer>> it = set.iterator();it.hasNext();){
        entrys.add(it.next());
}
用迭代把一个set转换成list。然后就可以使用方法进行排序来了。
结果是正确的,楼主可以尝试一下。

还想提醒楼主的是,尽量少用强制类型转换,容易出错,能用参数化类型(泛型)的地方尽量用泛型{:soso_e100:}
        
作者: 贠(yun)靖    时间: 2012-5-21 19:04
本帖最后由 贠(yun)靖 于 2012-5-21 19:44 编辑

package my.test;
import java.io.File;
import java.lang.reflect.Field;
import java.util.*;
public class TestTTT {

public static void main(String[] args)throws Exception {
  String[] strs = {"1988","1999"};
  birthday(strs );
}
public static void birthday(String[] birthdays) {
        Map<String, Integer> map = new TreeMap<String, Integer>();
        for(String birthday : birthdays) {
                if(map.get(birthday) == null) {
                        map.put(birthday, 1);
                } else {
                        int value = map.get(birthday) + 1;
                        map.put(birthday, value);
                }
        }        
        System.out.println(map);        
        Set<Map.Entry<String, Integer>> set = map.entrySet();        
        //Map.Entry<String, Integer>[] entrys = (Map.Entry<String, Integer>[])set.toArray();
        List list = new ArrayList();
        list.add(set);
        Collections.sort(list,new Comparator(){    //你这用的是Arrays中的sort方法 只能给数组排序,Collections中的sort方法是给List集合排序的
                public int compare(Object o1, Object o2) {               
                        Map.Entry<String, Integer> m1 = (Map.Entry<String, Integer>) o1;
                        Map.Entry<String, Integer> m2 = (Map.Entry<String, Integer>) o2;
                        if(m1.getValue() > m2.getValue()) {
                                return -1;
                        } else if(m1.getValue() < m2.getValue()) {
                                return 1;
                        } else  {
                                return 0;
                        }                        
                }        
        });
        System.out.println("日期重复次数从多到少排列为:");      
     这里直接迭代List集合就可以输出了   
        for(Iterator<Map.Entry<Integer, Integer>> it=list.iterator();it.hasNext();){
   
          System.out.println(it.next());     
  }
        
}
}


这是Arrays工具的
          sort(T[] a ,Comparator<? super T > c)根据指定比较器产生的顺序对指定对象数组进行排序。
这是Collections工具的
          sort(List<T> list,Comparator<? super T > c)根据指定比较器产生的顺序对指定列表进行排序

两个明显不一样,你要混用的话,肯定死定了 亲~~~
作者: 冯越    时间: 2012-5-21 19:41
云惟桉 发表于 2012-5-21 18:27
不好意思刚我看错了,用手机就是容易看漏代码不好意思噢。。
楼主的报错我没遇到,就是楼主说的【参数不匹 ...

Well Done!Thank you 啦!!!
作者: 冯越    时间: 2012-5-21 19:41
贠(yun)靖 发表于 2012-5-21 19:04
package my.test;
import java.io.File;
import java.lang.reflect.Field;

谢谢大版主了~ 嘿嘿
作者: 云惟桉    时间: 2012-5-21 19:57
贠(yun)靖 发表于 2012-5-21 19:04
package my.test;
import java.io.File;
import java.lang.reflect.Field;

版主果然是版主,还想到直接把set中的元素直接传递到list中

于是激发我的求知欲去查了一下文档。
发现版主应该是用list.addAll(set)吧?
以为貌似add方法好像不可以直接添加呢。
作者: 贠(yun)靖    时间: 2012-5-21 20:01
云惟桉 发表于 2012-5-21 19:57
版主果然是版主,还想到直接把set中的元素直接传递到list中

于是激发我的求知欲去查了一下文档。

add  addAll  都可以  两个区别很明显  至于这个提  用这两个方法 我觉得都可以  反正程序运行什么的都没问题  结果也可以运行出来的
作者: 林翔    时间: 2012-5-21 23:55
都是牛人,受教了




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