Java获取集合中重复的元素

需求

我们在下订单的时候,收件人的地址信息可能会有多个,现在的需求是把一些重复的地址信息删除掉。

姓名,电话,省,市,区,详细地址完全相同则认为是同一个收件人。

分析

地址是存在数据库的表里的,所以我们需要先查出每个收件人下重复的地址,再做数据库的删除操作。可以通过使用 HashSet 的 add 方法将地址列表中的地址一个一个的添加到 HashSet 中,add 方法有个返回值,类型为 Boolean,值为 true 表示添加成功,false 表示当前元素已经重复了,此时,可以将这个已经重复的元素添加到另一个集合中,即可完成对重复元素的收集。最后,再通过数据库操作把这些重复的元素删除即可。

实现

地址实体类:

import lombok.Data;

import java.util.Objects;

// 地址实体类
@Data
public class ErpReceiver {

    private Integer id;

    // 收件人名
    private String name;

    // 手机号码
    private String phone;

    // 省
    private String province;

    // 市
    private String city;

    // 区
    private String country;

    // 详细地址
    private String detailAddr;

    // 姓名,电话,省,市,区,详细地址相同则视为同一个地址
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ErpReceiver that = (ErpReceiver) o;
        return Objects.equals(name, that.name) &&
                Objects.equals(phone, that.phone) &&
                Objects.equals(province, that.province) &&
                Objects.equals(city, that.city) &&
                Objects.equals(country, that.country) &&
                Objects.equals(detailAddr, that.detailAddr);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, phone, province, city, country, detailAddr);
    }

    @Override
    public String toString() {
        return "ErpReceiver{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone='" + phone + '\'' +
                ", province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", country='" + country + '\'' +
                ", detailAddr='" + detailAddr + '\'' +
                '}';
    }
}

地址去重核心业务逻辑:

public static void main(String[] args) {
    List<ErpReceiver> receivers = Lists.newArrayList();

    ErpReceiver r1 = new ErpReceiver();
    r1.setId(1);
    r1.setName("张三");
    r1.setPhone("1395156854421");
    r1.setProvince("山东省");
    r1.setCountry("烟台市");
    r1.setCity("牟平区");
    r1.setDetailAddr("新建大街333");

    ErpReceiver r2 = new ErpReceiver();
    r2.setId(2);
    r2.setName("张三");
    r2.setPhone("1395156854421");
    r2.setProvince("山东省");
    r2.setCountry("烟台市");
    r2.setCity("牟平区");
    r2.setDetailAddr("新建大街333");

    ErpReceiver r3 = new ErpReceiver();
    r3.setId(3);
    r3.setName("李四");
    r3.setPhone("15758965478");
    r3.setProvince("浙江省");
    r3.setCountry("杭州市");
    r3.setCity("西湖区");
    r3.setDetailAddr("人才街");

    ErpReceiver r4 = new ErpReceiver();
    r4.setId(4);
    r4.setName("李四");
    r4.setPhone("15758965478");
    r4.setProvince("浙江省");
    r4.setCountry("杭州市");
    r4.setCity("西湖区");
    r4.setDetailAddr("人才街");

    ErpReceiver r5 = new ErpReceiver();
    r5.setId(5);
    r5.setName("王五");
    r5.setPhone("56565656");
    r5.setProvince("北京");
    r5.setCountry("北京");
    r5.setCity("天津");
    r5.setDetailAddr("666");

    ErpReceiver r6 = new ErpReceiver();
    r6.setId(6);
    r6.setName("王五");
    r6.setPhone("56565656");
    r6.setProvince("北京");
    r6.setCountry("北京");
    r6.setCity("天津");
    r6.setDetailAddr("666");

    ErpReceiver r7 = new ErpReceiver();
    r7.setId(7);
    r7.setName("王五");
    r7.setPhone("56565656");
    r7.setProvince("北京");
    r7.setCountry("北京");
    r7.setCity("天津");
    r7.setDetailAddr("666");

    receivers.add(r1);
    receivers.add(r2);
    receivers.add(r3);
    receivers.add(r4);
    receivers.add(r5);
    receivers.add(r6);
    receivers.add(r7);

    System.out.println("=============未去重的地址================");
    for (ErpReceiver rr : receivers) {
        System.out.println(rr);
    }

    List<ErpReceiver> duplicate = new ArrayList();

    HashSet<ErpReceiver> setRecivers = new HashSet<ErpReceiver>();
    for (ErpReceiver rr : receivers) {
        boolean flag = setRecivers.add(rr);
        // 返回false表示这个元素已经重复了,底层是调用对象的hashCode和equals方法判断对象是否相等的
        if (!flag) {
            duplicate.add(rr);
        }
    }

    System.out.println("==============去重之后的地址==============");
    for (ErpReceiver rr : setRecivers) {
        System.out.println(rr);
    }

    System.out.println("============重复的地址==============");
    for (ErpReceiver obj : duplicate) {
        System.out.println(obj);
    }
}

结果

Java获取集合中重复的元素_第1张图片

总结

地址列表只遍历了一遍,时间复杂度是O(n),虽然用了两个集合来存储重复的地址和不重复的地址但是他们元素的总个数是n,所以空间复杂度也是O(n)。

通过该算法既可以找到重复的元素,也可以获取到不重复的元素;既可以获得重复元素的个数,也可以获取到不重复元素的个数。

PS:HashSet 内部其实维护了一个 HashMap,HashMap底层是一个 Entry 类型的数组,向 HashSet 中 add 元素其实就是向 HashMap 中 put key-value 对,key 就是当前这个对象,value 是一个默认的不可变的 Object 对象,在向 HashMap 中 put 元素的时候会先调用 key 的 hashcode 方法计算键的 hash 值,以确定该元素存储在数组的哪个位置,如果计算出来的位置已经存在元素了,继续调用 key 的 equals 方法去判断是否是相同的元素,如果返回 false 不相同则默认以链表的形式追加到那个已存在的元素的尾部,如果返回 true 相同则不添加。

当然,我们也可以直接查出所有的地址信息,通过 HashSet 的 addAll 方法直接获取去重以后的地址列表,把原来的地址全部删掉,然后再把 HashSet 中去过重的地址全部添加到表中。但是,这种方式会使地址的 id 发生改变(MySql 自增或 Oracle 的序列),如果有通过地址 id 关联的数据,那么 id 修改之后将无法获取到这些数据,所以,安全起见还是尽量只删除那些该删除的数据。

关注我的微信公众号(曲健磊的个人随笔),获取更多精彩内容:
Java获取集合中重复的元素_第2张图片

你可能感兴趣的:(【JavaSE基础部分】)