List、Set、Map三大集合的排序问题

学了这么长时间的集合,是否会对这三大集合进行排序呢?
首先,了解一下Comparator和Comparable
通常,要对一个存储在集合内的实体类进行排序时,有两种策略:1. 实体类实现Comparable接口;2. 创建集合时指定Comparator,即实现Comparator接口;
为了区分这两个接口,通过称实现Comparable的实体类是可排序的,而Comparator则称呼为比较器。
下面使用具体的代码来使用这两个接口(按照使用的集合分别进行讲解)

List

List中存储的是Integer等数据类型的话,直接使用Collections.sort(List<E> list)或者Collections.sort(List<E> list, Comparator<? super T> c)进行排序。这里讲的是自定义类的排序。

  1. 实现Comparable的方式
package sort.list;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @ClassName Demo2
 * @Description: 按照User的年龄进行排序
 * @Author 田清波
 * @Mail tqb820965236@163.com
 * @Date 2019/8/13 16:34
 * @Version v1.0
 */
public class Demo2 {
    @Test
    public void test(){
        User user1 = new User("zhangsan", 23);
        User user2 = new User("lisi", 25);
        User user3 = new User("wangwu", 20);

        List<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);

        System.out.println("未排序:" + list);
        Collections.sort(list);
        System.out.println("已排序:" + list);
    }
}

class User implements Comparable<User>{
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(User o) {
        /**
         * 指定对象减去此对象 - 降序
         * 此对象减去指定对象 - 升序
         */
        // System.out.println(o.age - this.age);
        return this.age - o.age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 实现Comparator的方式
package sort.list;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @ClassName Demo2
 * @Description: 按照User的年龄进行排序
 * @Author 田清波
 * @Mail tqb820965236@163.com
 * @Date 2019/8/13 16:34
 * @Version v1.0
 */
public class Demo2 {
    @Test
    public void test(){
        User user1 = new User("zhangsan", 23);
        User user2 = new User("lisi", 25);
        User user3 = new User("wangwu", 20);

        List<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);

        System.out.println("未排序:" + list);
        /**
         * 通过匿名内部类进行实现,即指定排序的方式
         */
        Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                /**
                 * o2 - o1 : 降序
                 * o1 - o2 : 升序
                 */
                return o2.getAge() - o1.getAge();
            }
        });
        System.out.println("已排序:" + list);
    }
}

class User {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Set

这里以我春招面试途牛的一道题作为讲解,当时真的不会,所以自然面试没通过(=_=),下来做了一下非常的懊悔!!!
题目:
现在存在这么个需求,就是对学生进行排序操作(升序降序都实现),前提是不能存在相同年龄的学生(当然我觉得这是不合理的)在进行学生添加的时候,相同年龄不再进行添加。
解决思路:

1. 首先使用Set集合(Set集合不允许出现相同的数据,即数据唯一,TreeSet(使用该类添加自定义的实体类时,要么实现可排序接口,要么自定义比较器)这里需要知道TreeSet的存储结构数据是排好序的。
2. 用户Person实现equals(供用户调用)和hashcode方法(在进行数据add的时候,默认调用hashcode方法)
3. hashcode通过age计算hash值,这样保证了数据的唯一性
4. 排序的话两种实现方式
	1. Person实现可排序接口Comparable
	2. 创建集合时指定比较器

代码体现:

package sort.set;

import org.junit.Test;

import java.util.*;

/**
 * @ClassName SetToList
 * @Description: 途牛面试题
 * @Author 田清波
 * @Mail tqb820965236@163.com
 * @Date 2019/8/13 21:20
 * @Version v1.0
 */
public class SetToList {

    @Test
    public void test(){
        Set<Person> set = new TreeSet<>(new Comparator<Person>() {
            /**
             * 原先的排序方式失效(升序)
             * @param o1
             * @param o2
             * @return
             */
            @Override
            public int compare(Person o1, Person o2) {
                return o2.getAge() - o1.getAge();// 降序
            }
        });
        Person person1 = new Person("zhangsan" ,11);
        Person person2 = new Person("lisi" ,14);
        Person person3 = new Person("wangwu" ,13);
        Person person4 = new Person("lisi" ,13);

        set.add(person1);
        set.add(person2);
        set.add(person3);
        set.add(person4);

        System.out.println(set.size());
        System.out.println(set);

    }
}

class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    /**
     * 重写equals和hashCode方法
     *      判断是否是一个对象
     *          (途牛面试题目,当时真的不会做)
     *          题目:现在存在这么个需求,就是对用户进行排序操作(升序降序都实现),前提是不能存在相同年龄的用户(当然我觉得这是不合理的)
     *               在进行用户添加的时候,相同年龄不再进行添加。
     *          解决思路:
     *              首先使用Set集合(Set集合不允许出现相同的数据,即数据唯一,TreeSet(使用该类添加自定义的实体类时,要么实现可排序接口,要么自定义比较器) 数据是排序的)
     *              用户Person实现equals(供用户调用)和hashcode方法(在进行数据add的时候,默认调用hashcode方法)
     *              hashcode通过age计算hash值
     *              这样保证了数据的唯一性
     *              排序的话两种实现方式
     *                  1. Person实现可排序接口Comparable
     *                  2. 创建集合时指定比较器
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!(o instanceof Person))
            return false;
        Person person = (Person) o;
        return person.age == this.age;
    }

    /**
     * 对象相同的话,哈希值一定相同
     * 对象不相同的话,哈希值不一定不相同(存在哈希碰撞)
     * 依靠这个性质判断对象是否相同
     * 供散列表进行调用 HashSet HashMap...
     * @return
     */
    @Override
    public int hashCode() {
        return Objects.hash(age);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
	/*
    @Override
    public int compareTo(Person o) {
        return this.age - o.age; // 升序
    }
    */
}
Map

题目:按照水果的个数进行排序
直接上代码(还可以使用List进行实现,即针对List进行排序再转换,这里直接使用TreeSet,TreeMap也可以实现):

package sort.map;

import org.junit.Test;

import java.util.*;

/**
 * @ClassName MapSort
 * @Description: 对Map进行排序
 * @Author 田清波
 * @Mail tqb820965236@163.com
 * @Date 2019/8/15 9:02
 * @Version v1.0
 */
public class MapSort {
    @Test
    public void test(){
        HashMap<Fruit, Integer> map = new HashMap<>();
        Fruit fruit1 = new Fruit("苹果");
        Fruit fruit2 = new Fruit("草莓");
        Fruit fruit3 = new Fruit("梨");
        Fruit fruit4 = new Fruit("西瓜");
        Fruit fruit5 = new Fruit("香蕉");

        map.put(fruit1, 9);
        map.put(fruit2, 2);
        map.put(fruit3, 8);
        map.put(fruit4, 5);
        map.put(fruit5, 1);

        Map<Fruit, Integer> sort = sort(map);
        Set<Map.Entry<Fruit, Integer>> entries = sort.entrySet();
        for (Map.Entry<Fruit, Integer> entry : entries){
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
    }

    public Map<Fruit, Integer> sort(Map<Fruit, Integer> map){
        /**
         * 将Map转为Set
         */
        Set<Map.Entry<Fruit, Integer>> entries = map.entrySet();
        TreeSet<Map.Entry<Fruit, Integer>> set = new TreeSet<>(new Comparator<Map.Entry<Fruit, Integer>>() {
            @Override
            public int compare(Map.Entry<Fruit, Integer> o1, Map.Entry<Fruit, Integer> o2) {
                return o1.getValue() - o2.getValue();
            }
        });
        /**
         * 向TreeSet中添加数据
         */
        for (Map.Entry<Fruit, Integer> entry : entries){
            set.add(entry);
        }
        /**
         * 将Set转为LinkHashMap(有序)返回
         */
        LinkedHashMap<Fruit, Integer> resMap = new LinkedHashMap<>();
        for (Map.Entry<Fruit, Integer> entry : set){
            resMap.put(entry.getKey(), entry.getValue());
        }
        return resMap;
    }
}

class Fruit {
    private String name;
    private String remark;

    public Fruit() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Fruit(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", remark='" + remark + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值