Java中Set的巧妙用法---查找重复元素/去重/排序

目录

1. Set特性:

3. TreeSet

3.1定制排序(比较器排序)

3.2自然排序:

4. LinkedHashSet


在日常开发中不可避免会遇到需要去重,或者查找重复元素,下面给介绍一种效率比较高的方法,时间复杂度为O(n)      

1. Set特性:

①不允许出现重复元素;

②集合中的元素位置无顺序;

③有且只有一个值为null的元素。

Set的主要实现类有:HashSet,TreeSet,LinkedHashSet,这几个类得一共同点都是相同的只能保存一份。

2. HashSet

HashSet能够较快的获取集合中的元素,它是通过hashCode和equals方法来判断两个对象是否相等,如果hashCode值一样则会进一步调用equals方法来判断是否相等,如果为true则表示项目,如果为false则表示不同。

简单示例代码如下:

Student类


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

    private String studentId;

    private String phone;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", studentId='" + studentId + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

Main测试方法如下:


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MainTest {

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1234"));
        list.add(new Student("李四", "1234","2222"));
        list.add(new Student("李四", "1234","3333"));
        list.add(new Student("王五", "4567","2222"));
        list.add(new Student("老六", "8910","2222"));

        Set<Student> set = new HashSet<>();
        list.forEach(item->{
            if (!set.add(item)){
                System.out.println("该学生重复:" + item);
            }
        });
        System.out.println(set.size() + ": " + set);


    }



}

输出结果如下:

HashSet的add方法会返回一个布尔类型的值,如果为true则表示插入成功,如果为false则插入失败(插入失败就是出现了重复的元素)。你会发现默认的是student类的三个属性name,student,phone相等才会判断相等。

进阶实例:

需求:只要姓名和学号相同的学生则认为是同一个学生

根据需求我们需要重写student类的hashcode和equals方法使其只需要判断姓名和学号即可。代码如下:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Objects;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

    private String studentId;

    private String phone;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", studentId='" + studentId + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("我是equals方法");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        //在这里默认会使用name,studentId, phone三个属性,我们只需要改为name和studentId属性即可
//        return Objects.equals(name, student.name) && Objects.equals(studentId, student.studentId) && Objects.equals(phone, student.phone);
        //根据需求我们只需要该为只判断name和studentId即可
        return Objects.equals(name, student.name) && Objects.equals(studentId, student.studentId);
    }

    @Override
    public int hashCode() {
        System.out.println("我是hashCode方法");
        //Objects.hash方法的参数是一个可变参数可以根据自己需求来变动
        //默认是使用类的所有属性的hashcode值来判断hashcode是否相同
//        return Objects.hash(name, studentId, phone);
        //根据需求我们只需要给成name和studentId即可
        return Objects.hash(name, studentId);
    }
}

Main测试方法没变化:


import com.example.testdemo.entity.Student;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MainTest {

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1234"));
        list.add(new Student("李四", "1234","2222"));
        list.add(new Student("李四", "1234","3333"));
        list.add(new Student("王五", "4567","2222"));
        list.add(new Student("老六", "8910","2222"));

        Set<Student> set = new HashSet<>();
        list.forEach(item->{
            if (!set.add(item)){
                System.out.println("该学生重复:" + item);
            }
        });
        System.out.println(set.size() + ": " + set);


    }



}

输出结果如下:

以上这种方法也是用的最多的。

3. TreeSet

TreeSet也不能插入重复元素并且能够进行排序(通过自然排序和定制排序)

3.1定制排序(比较器排序)

代码实例:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

    private String studentId;

    private String phone;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", studentId='" + studentId + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}
import java.util.*;

public class MainTest {

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1234"));
        list.add(new Student("李四", "1234","2222"));
        list.add(new Student("李四", "1234","3333"));
        list.add(new Student("王五", "4567","2222"));
        list.add(new Student("老六", "8910","2222"));

        TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getName().compareTo(o2.getName()) + o1.getStudentId().compareTo(o2.getStudentId());
            }
        });
        list.forEach(item->{
            if (!set.add(item)){
                System.out.println("该学生重复:" + item);
            }
        });
        System.out.println(set.size() + ": " + set);

    }
}

其中compare方法的返回值如果是0则表示两者相等,如果是小于0则表示第一个对象o1小于第二个对象o2,如果大于0则表示o1大于o2(compare方法既有排序的作用也有去重的作用)

3.2自然排序:

实现comparable接口的compare方

代码如下:


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Comparable<Student> {

    private String name;

    private String studentId;

    private String phone;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", studentId='" + studentId + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.getName().compareTo(o.getName()) + this.getStudentId().compareTo(o.getStudentId());
    }
}

import com.example.testdemo.entity.Student;

import java.util.*;

public class MainTest {

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1111"));
        list.add(new Student("张三", "1234","1234"));
        list.add(new Student("李四", "1234","2222"));
        list.add(new Student("李四", "1234","3333"));
        list.add(new Student("王五", "4567","2222"));
        list.add(new Student("老六", "8910","2222"));

        TreeSet<Student> set = new TreeSet<>();
        list.forEach(item->{
            if (!set.add(item)){
                System.out.println("该学生重复:" + item);
            }
        });
        System.out.println(set.size() + ": " + set);

    }
}

看自己喜欢用哪一个即可。

4. LinkedHashSet

LinkedHashSet是HashSet和LinkedHashMap的结合体。它既有HashSet的快速查找和不允许重复元素的特性,又有LinkedHashMap的有序性和迭代器的快速遍历特性。因此,在需要保持元素顺序的情况下,我们可以使用LinkedHashSet。

心中若有光芒,脚下自有道路,勇往直前,无畏前行!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值