文档章节

JAVA比较器中comparator的使用

daxiongdi
 daxiongdi
发布于 10/15 14:09
字数 2156
阅读 7
收藏 0

一个专用的比较器Comparator

Comparator是一个专用的比较器,当一个不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparator体现了一种策略模式,即不改变对象自身,而用一个策略对象来改变它的行为。

import java.util.Comparator;

import java.util.Iterator;

import java.util.TreeSet;

class Student {

    private String name;

    private float score;

    public Student(String name, float score) {

        this.name = name;

        this.score = score;

    }

    public String getName() {

        return name;

    }

    public float getScore() {

        return score;

    }

    @Override

    public String toString() {

        return String.valueOf(this.name + ": " + this.score);

    }

}

class StudentComparator implements Comparator<Student> {

    @Override

    public int compare(Student o1, Student o2) {

        if (o2.getScore() - o1.getScore() > 0) {

            return 1;

        } else if (o2.getScore() - o1.getScore() < 0) {

            return -1;

        } else {

            return 0;

        }

    }

}

public class ComparableDemo {

    public static void main(String[] args) {

        TreeSet<Student> set = new TreeSet<Student>(new StudentComparator());

        set.add(new Student("zhangsan", 79));

        set.add(new Student("lisi", 95));

        set.add(new Student("wangwu", 87));

        for (Iterator<Student> iter = set.iterator(); iter.hasNext();) {

            System.out.println(iter.next());

        }

    }

}

打印结果:

lisi: 95.0

wangwu: 87.0

zhangsan: 79.0

说明

Comparator接口有两个方法,一个是compare方法,另外一个是equals()方法,但是大多数情况下,在一个类实现Comparator接口时,是不需要重写equals方法的,这是因为这个类继承了Object的equals方法。

Comparable接口和Comparator接口的区别

它们两个都是用来实现外汇返佣http://www.fx61.com/集合中元素的比较、排序的。

Comparable是在集合内部定义的方法实现的排序,位于java.util包下

Comparator是在集合外部实现的排序,位于java.lang包下。

在一个又一个类设计完成后,或许我们最初没有考虑到类的比较问题,没有对Comparable接口进行实现,没有关系,我们可以通过Comparator接口来完成,并且无需改变之前完成的类的构建。

Collections.sort(list,new Comparator<Integer>(){

            public int compare(Integer str1,Integer str2){

                String s1=str1+""+str2;

                String s2=str2+""+str1;

                return s1.compareTo(s2);

            }

        });

comparator 是javase中的接口,位于java.util包下,该接口抽象度极高,有必要掌握该接口的使用

大多数文章告诉大家comparator是用来排序,但我想说排序是comparator能实现的功能之一,他不仅限于排序

排序例子:

题目描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

代码实现:

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

pblic class Solution {

    public String PrintMinNumber(int [] s) {

        if(s==null) return null;

        String s1="";

        ArrayList<Integer> list=new ArrayList<Integer>();

        for(int i=0;i<s.length;i++){

             list.add(s[i]);

        }

        Collections.sort(list,new Comparator<Integer>(){

            public int compare(Integer str1,Integer str2){

                String s1=str1+""+str2;

                String s2=str2+""+str1;

                return s1.compareTo(s2);

            }

        });

         for(int j:list){

                s1+=j;

             }

        return s1;

    }

}

一般需要做比较的逻辑都可以使用的上Comparator,最常用的场景就是排序和分组,排序常使用Arrays和Collections的sort方法,而分组则可以使用提供的divider方法。

排序和分组的区别在于: 

排序时,两个对象比较的结果有三种:大于,等于,小于。 

分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)

package com.java.demo.Comparator;

import java.sql.Date;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.List;

/**

 * 运号单流程

 *

 * @author Administrator

 */

public class TestComparator {

    /**

     * 测试main方法

     * @param args

     */

    public static void main(String[] args) {

        List<Step> steps = new ArrayList<Step>();

        Step s1 = new Step("2012-07-10", "北京1");

        Step s2 = new Step("2012-07-11", "北京2");

        Step s3 = new Step("2012-07-12", "北京3");

        Step s4 = new Step("2012-07-09", "北京4");

        Step s5 = new Step("2012-07-11", "北京22");

        steps.add(s1);

        steps.add(s2);

        steps.add(s3);

        steps.add(s4);

        steps.add(s5);

        sort(steps);

    }

    private static void sort(List<Step> steps) {

        //对集合对象进行排序

        MyStepComparator comparator = new MyStepComparator();

        Collections.sort(steps, comparator);

        if(steps != null && steps.size() > 0) {

            for(Step step:steps) {

               System.out.print(step.getAcceptTime() + ":");

               System.out.println(step.getAcceptAddress());

            }

        }

    }

    /**

     * 对Step类进行排序比较的工具类

     *

     * @author Administrator

     *

     */

    static class MyStepComparator implements Comparator<Step>{

        /**

         * 如果o1小于o2,返回一个负数;如果o1大于o2,返回一个正数;如果他们相等,则返回0;

         */

        @Override

        public int compare(Step o1, Step o2) {

            Date acceptTime1 = Date.valueOf(o1.getAcceptTime());

            Date acceptTime2 = Date.valueOf(o2.getAcceptTime());

            //对日期字段进行升序,如果欲降序可采用before方法

            if(acceptTime1.after(acceptTime2)) {

                return 1;

            } else if(acceptTime1.before(acceptTime2)) {

                return -1;

            } else {

                return 0;

            }

        }

    }

    

    /**

     * 需要比较的对象

     * @author maodejun

     *

     */

    static class Step{

        /** 处理时间 */

        private String acceptTime = "";

        /** 快件所在地点 */

        private String acceptAddress = "";

        public Step() {

            super();

        }

        public Step(String acceptTime, String acceptAddress) {

            super();

            this.acceptTime = acceptTime;

            this.acceptAddress = acceptAddress;

        }

        public String getAcceptTime() {

            return acceptTime;

        }

        public void setAcceptTime(String acceptTime) {

            this.acceptTime = acceptTime;

        }

        public String getAcceptAddress() {

            return acceptAddress;

        }

        public void setAcceptAddress(String acceptAddress) {

            this.acceptAddress = acceptAddress;

        }

    }

}

排序的算法是我们最常用的算法,初学程序,每个人都尝试过排序。但只是局限于简单的排序。

如将下列数字进行排序

1,3,5,8,3,6

于是我们得出结果

1,3,3,5,6,8

将下列字母(字符)进行排序

a,i,e,f,w,s

于是我们得出结果

a,e,f,i,s,w

但是我们遇到的情况就不是如此简单了。如给公司里的商品进行排序,我们很轻易的想到按照商品的名称排序不就完了,而且简单明了。但现实并如我们相信般简单。同一商品名称可以有不同的批次,进货时间,可能还会有单价的不同。显然只根据商品名称排序是不合理的。

再举个简单例子然后用程序实现。如公司要将员工进行排序(不要说领导排在前面),假设我们的需求比较复杂。先进行姓排序,谁的姓拼音靠前,谁就排前面。然后对名字进行排序。恩.如果同名,女性排前头。如果名字和性别都相同,年龄小的排前头。ok,一个也不算复杂的需求。

如果对java比较熟悉的会知道java.util.Comparator 接口。要实现里面的函数

int compare(Object o1, Object o2) 返回一个基本类型的整型,返回负数表示o1 小于o2,返回0 表示o1和o2相等,返回正数表示o1大于o2。

于是我们设计的人员类要有几个变量,firstname,lastname,sex,age分别表示姓,名,性别,年龄。

public class Person {

String firstname,lastname;

Boolean sex;

Integer age;

public Person(String firstname,String lastname,Boolean sex,Integer age) {

    this.firstname = firstname;

    this.lastname = lastname;

    this.sex = sex;

    this.age = age;

}

public String getFirstName() {

     return firstname;

   }

   public String getLastName() {

     return lastname;

   }

   public Boolean getSex() {

      return sex;

    }

    public Integer getAge() {

      return age;

    }

//为了输入方便,重写了toString()

public String toString()

    {

      return firstname +" "+lastname+" "+(sex.booleanValue()?"男":"女")+" "+age;

    }

}

//end person

下面是要实现比较器

public class Comparators {

public static java.util.Comparator getComparator() {

    return new java.util.Comparator() {

      public int compare(Object o1, Object o2) {

        if (o1 instanceof String) {

          return compare( (String) o1, (String) o2);

        }

       else if (o1 instanceof Integer) {

          return compare( (Integer) o1, (Integer) o2);

        }

       else if (o1 instanceof Person) {

      return compare( (Person) o1, (Person) o2);

    }

        else {

          System.err.println("未找到合适的比较器");

          return 1;

        }

      }

      public int compare(String o1, String o2) {

        String s1 = (String) o1;

        String s2 = (String) o2;

        int len1 = s1.length();

        int len2 = s2.length();

        int n = Math.min(len1, len2);

        char v1[] = s1.toCharArray();

        char v2[] = s2.toCharArray();

        int pos = 0;

        while (n-- != 0) {

          char c1 = v1[pos];

          char c2 = v2[pos];

          if (c1 != c2) {

            return c1 - c2;

          }

          pos++;

        }

        return len1 - len2;

      }

      public int compare(Integer o1, Integer o2) {

        int val1 = o1.intValue();

        int val2 = o2.intValue();

        return (val1 < val2 ? -1 : (val1 == val2 ? 0 : 1));

      }

      public int compare(Boolean o1, Boolean o2) {

         return (o1.equals(o2)? 0 : (o1.booleanValue()==true?1:-1));

       }

      public int compare(Person o1, Person o2) {

        String firstname1 = o1.getFirstName();

        String firstname2 = o2.getFirstName();

        String lastname1 = o1.getLastName();

        String lastname2 = o2.getLastName();

        Boolean sex1 = o1.getSex();

        Boolean sex2 = o2.getSex();

        Integer age1 = o1.getAge();

        Integer age2 = o2.getAge();

        return (compare(firstname1, firstname2) == 0 ?

                (compare(lastname1, lastname2) == 0 ? (compare(sex1, sex2) == 0 ? (compare(age1, age2) == 0 ? 0 :

                 compare(age1, age2)) :

                 compare(sex1, sex2)) :

                 compare(lastname1, lastname2)) :

                compare(firstname1, firstname2));

      }

    };

}

}

以上代码有可能因为浏览器的布局自动换行。

compare(Person o1, Person o2)的返回值看起来比较别扭。最简单的是

    public int compare(Boolean o1, Boolean o2) {

         return (o1.equals(o2)? 0 : (o1.booleanValue()==true?1:-1));

       }

o1和o2相等返回0,否则o1如果是true 就表示o1大于o2。

再尝试输出结果看看

public class Main {

public Main() {

}

public static void main(String[] args) {

    Person[] person = new Person[] {

         new Person("ouyang", "feng", Boolean.TRUE, new Integer(27)),

         new Person("zhuang", "gw", Boolean.TRUE, new Integer(27)),

         new Person("zhuang", "gw", Boolean.FALSE, new Integer(27)),

         new text.Person("zhuang", "gw", Boolean.FALSE, new Integer(2)),

     };

     for (int i = 0; i < person.length; i++) {

       System.out.println("before sort=" + person[i]);

     }

     java.util.Arrays.sort(person, Comparators.getComparator());

for (int i = 0; i < person.length; i++) {

    System.out.println("after sort=" + person[i]);

}

}

}

输出结果:

before sort=ouyang feng 男 27

before sort=zhuang gw 男 27

before sort=zhuang gw 女 27

before sort=zhuang gw 女 2

after sort=ouyang feng 男 27

after sort=zhuang gw 女 2

after sort=zhuang gw 女 27

after sort=zhuang gw 男 27

© 著作权归作者所有

daxiongdi
粉丝 0
博文 29
码字总数 65176
作品 0
长沙
私信 提问
Java PriorityQueue && PriorityBlockingQueue

Java PriorityQueue && PriorityBlockingQueue 我们知道队列是遵循先进先出(First-In-First-Out)模式的,但有些时候需要在队列中基于优先级处理对象。举个例子,比方说我们有一个每日交易时...

秋风醉了
2015/01/12
208
0
似懂非懂 Comparable和 Comparator

在java中提供了两种排序方式:Comparable和 Comparator,它们两个看起来非常的相似,在不是很了解的情况下不知道如何使用,什么情况下使用哪个进行排序,接下来就看下它们的一个区别和使用方...

tsmyk0715
2018/09/29
1K
0
一起来学Java8(四)——复合Lambda

在中我们学习了Lambda表达式的基本用法,现在来了解下复合Lambda。 Lambda表达式的的书写离不开函数式接口,复合Lambda的意思是在使用Lambda表达式实现函数式接口抽象方法后,还可以再次调用...

猿敲月下码
10/23
61
0
java集合入门和深入学习,看这篇就差不多了

集合框架: Java中的集合框架大类可分为Collection和Map;两者的区别: Collection是单列集合;Map是双列集合 Collection中只有Set系列要求元素唯一;Map中键需要唯一,值可以重复 Collecti...

sihailoveyan
2018/05/04
184
2
Java集合 (SortedSet)

java.util.SortedSet接口是java.util.Set接口的一个子接口。处了元素顺序由 自身内部进行排序外其它与Set行为一致(可以说在Set基础上增加自身排序功能) 默认该排序是由自身内部的自然排序(...

Kevin-air
2014/01/07
69
0

没有更多内容

加载失败,请刷新页面

加载更多

射频 - 灵敏度

灵敏度是一个规格指示器,显示设备接收信号的程度,并在“令人满意的错误率”内对其进行解码。 (“令人满意的错误率”的错误率应该有多低,通常由每个应用自己的规范定义)。灵敏度以功率电...

demyar
29分钟前
6
0
java @Contract 的pom坐标

应用 @Contract(value = "_ -> param1", pure = true) int getNum(int i){ return i;} pom <dependency> <groupId>org.jetbrains</groupId> ......

macker
32分钟前
6
0
git 拉取指定分支

//默认(xxx指的是url)git clone xxx//指定分支(xxx指的是url)git clone -b 分支名 xxx

uug
40分钟前
7
0
阿里云报SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed:根本原因

报错内容如下: 系统架构如下: 15台阿里云服务器集群(主服放在华南可用区A区,其他14台分别部署在A/B/C/D/E区都有) + 1台阿里云Reids(A区) + 5台阿里云mysql服务器(1主4从)(A区) 报错请况: 这个...

银装素裹
42分钟前
6
0
Android Handler理解

Handler是什么 Handler是Android 线程间通信工具类。 一般用于子线程向主线程发送消息,将子线程中执行结果通知主线程,从而在主线程中执行UI更新操作。 源码角度理解 Handler负责发送(sen...

二营长的意大利炮手
48分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部