数组去重,你会几种方式?

前言

数据去重是项目中经常出现的应用场景,并且面试中可能也会问到,那么你会几种数组去重方式呢?

实战

使用额外空间去重
List<String> list = Arrays.asList("java""html""js""sql""java");

@Test
public void test8() {
  List<String> newList = new ArrayList<>();
  for (String el : list) {
    if(!newList.contains(el)) {
      newList.add(el);
    }
  }

  System.out.println(newList);
}

优点:实现简单、并且在循环判断过程中可以增加额外操作

缺点:需要一个额外空间大小的数组,浪费空间,多行代码实现

Set集合自动去重
List<String> list = Arrays.asList("java""html""js""sql""java");

@Test
public void test8() {
   Set<String> set = new HashSet<>(list);
   List<String> newList = new ArrayList<>(set);

   System.out.println(newList);
}

优点:利用Set集合的不重复特性去重更简单

缺点:使用额外空间,需要来回转换,不太优雅

Java8一键去重(distinct)
List<String> list2 = Arrays.asList("java""html""js""sql""java");

 @Test
 public void test9() {
    // java8 stream-api去重
   list2.stream()
      .distinct()
      .forEach(System.out::println);
 }

优点:java8新特性,流式操作简单方便(和sql一样),代码优雅

缺点:无法在去重的过程中进行额外操作

distinct去重注意事项

既然这么好用,那distinct是通过什么去重的呢?如果是引用类型,是通过地址去重还是通过某些字段去重呢?

  • distinct去重失效示例代码

    List<Employee> list = Arrays.asList(
                new Employee( "小明"18),
                new Employee( "赵六"38),
                new Employee( "张三"6),
                new Employee( "小明"18)
        );

    class Employee {
        private String name;
        private Integer age;

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

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


    @Test
    public void test9() {
        list.stream()
          .distinct()
          .forEach(System.out::println);
    }

    控制台输出:

    Employee{name='小明', age=18}
    Employee{name='赵六', age=38}
    Employee{name='张三', age=6}
    Employee{name='小明', age=18}

    结果:使用自定义对象distinct无法去重,难道distinct无法作用引用类型吗?但是刚才的String也是引用类型,但是也可以去重。自定义的对象EmployeeString有什么区别吗?没错,就是hashcode()equals()方法,String已经重写了这两个方法,自定义的Employee没有重写这两个方法。

    注意:只要是涉及MapSet这种去重的集合,或者Java8的distinct去重,都是通过hashcode()equals来作为数据去重的依据,所以要注意重写这两个方法

  • 修改测试

    class Employee {
        private String name;
        private Integer age;
         
        ...
        
       // 重写equals和hashcode方法
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Employee employee = (Employee) o;
            return Objects.equals(name, employee.name) &&
              Objects.equals(age, employee.age);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
       
        ...
    }

    @Test
    public void test9() {
        list.stream()
          .distinct()
          .forEach(System.out::println);
    }

    控制台输出:

    Employee{name='小明', age=18}
    Employee{name='赵六', age=38}
    Employee{name='张三', age=6}

    重写hashcodeequals可以实现去重。

小总结

无论使用Set集合去重还是使用Java8的新特性stream流的distinct去重,都是通过hashcode()equals()自定义的策略进行去重。


原文始发于微信公众号(指尖上的代码):数组去重,你会几种方式?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/40001.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!