快速找出两个List中某些特定属性相同的实体类

一、HashSet

        HashSet是一个基于哈希表(HashMap)实现,元素不可重复的集合,通过这些特点可以快速找出重复的元素。

        HashMap中当元素的hash值相同时,桶位置索引的计算值就会相同,且计算值比较"=="和equals结果为true,认为key相等。通过重写hashCode与equals方法使得只根据类的某些属性值进行比较,从而判断两个元素是否“重复”。

二、实现

重写hashcode和equals方法

    public class Bean<T, K> {

        /**
         * 需要比较的元素
         */
        private final T data;

        /**
         * get方法
         */
        private final Function<T, K>[] getProperty;

        public Bean(T t, Function<T, K>[] getProperty) {
            this.data = t;
            this.getProperty = getProperty;
        }

        public T getData() {
            return data;
        }

        @Override
        public int hashCode() {
            if (ArrayUtil.isEmpty(getProperty)) {
                return data.hashCode();
            }
            // 参考lombok
            int result = 1;
            for (Function<T, K> get : getProperty) {
                K property = get.apply(data);
                result = result * 59 + (property == null ? 43 : property.hashCode());
            }
            return result;
        }

        @Override
        public boolean equals(Object o) {
            if (ArrayUtil.isEmpty(getProperty)) {
                return data.equals(((Bean<T, K>) o).data);
            }
            boolean result = Boolean.TRUE;
            for (Function<T, K> get : getProperty) {
                K property = get.apply(data);
                K property2 = get.apply(((Bean<T, K>) o).data);
                result = result && property.equals(property2);
            }
            return result;
        }
    }

方法

利用HashSet找到“重复”元素

    @SafeVarargs
    public static <T, K> List<T> findDuplicateElements(List<T> list1, List<T> list2, Function<T, K>... getProperty) {
        Assert.notEmpty(list1, "list is empty");
        Assert.notEmpty(list2, "list is empty");
        Set<Bean<T, K>> beanSet = list1.stream().map(a -> new Bean<>(a, getProperty)).collect(Collectors.toSet());
        Set<T> duplicateSet = new HashSet<>();

        for (T element : list2) {
            if (beanSet.contains(new Bean<>(element, getProperty))) {
                duplicateSet.add(element);
            }
        }
        return new ArrayList<>(duplicateSet);
    }

测试

例子

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserRole  {
        String roleName;
        Integer level;
        String fiveElements;
    }
    public static void main(String[] args) {
        //测试一
        List<UserRole> list1 = new ArrayList<>();
        list1.add(new UserRole("骑士", 12, "earth"));
        list1.add(new UserRole("骑士", 12, "earth"));
        list1.add(new UserRole("牧师", 12, "wood"));
        list1.add(new UserRole("法师", 13, "fire"));
        List<UserRole> list2 = new ArrayList<>();
        list2.add(new UserRole("骑士", 12, "fire"));
        list2.add(new UserRole("法师", 15, "fire"));
        System.out.println("查找两个集合中职业相同的UserRole");
        System.out.println(findDuplicateElements(list1, list2, UserRole::getRoleName));
        System.out.println("查找两个集合中五行属性相同、等级相同的UserRole");
        System.out.println(findDuplicateElements(list1, list2, UserRole::getRoleName, UserRole::getLevel));
    }

输出如下

三、工具类

import cn.hutool.core.util.ArrayUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.Assert;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class BeanComparatorUtil {

    @SafeVarargs
    public static <T, K> Boolean equalsByProperty(T o1, T o2, Function<T, K>... getProperty) {
        return CollectionUtils.isNotEmpty(findDuplicateElements(Collections.singletonList(o1), Collections.singletonList(o2), getProperty));
    }

    /**
     * 查找两个集合中属性相同的重复元素
     */
    @SafeVarargs
    public static <T, K> List<T> findDuplicateElements(List<T> list1, List<T> list2, Function<T, K>... getProperty) {
        Assert.notEmpty(list1, "list is empty");
        Assert.notEmpty(list2, "list is empty");
        Set<Bean<T, K>> beanSet = max(list1, list2).stream().map(a -> new Bean<>(a, getProperty)).collect(Collectors.toSet());
        Set<T> duplicateSet = new HashSet<>();

        for (T element : min(list1, list2)) {
            if (beanSet.contains(new Bean<>(element, getProperty))) {
                duplicateSet.add(element);
            }
        }
        return new ArrayList<>(duplicateSet);
    }

    /**
     * 查找两个集合中属性相同的不重复元素
     */
    @SafeVarargs
    public static <T, K> List<T> findUnDuplicateElements(List<T> list1, List<T> list2, Function<T, K>... getProperty) {
        Assert.notEmpty(list1, "list is empty");
        Assert.notEmpty(list2, "list is empty");
        return Stream.of(list1, list2).flatMap(Collection::stream)
                .map(a -> new Bean<>(a, getProperty)).collect(Collectors.toSet())
                .stream().map(Bean::getData).collect(Collectors.toList());
    }

    /**
     * 只返回sourceList中不相同的元素
     */
    @SafeVarargs
    public static <T, K> List<T> findUnDuplicateElementsFromSourceList(List<T> sourceList, List<T> compareList, Function<T, K>... getProperty) {
        Assert.notEmpty(sourceList, "list is empty");
        Assert.notEmpty(compareList, "list is empty");
        Set<Bean<T, K>> beanSet = compareList.stream().map(a -> new Bean<>(a, getProperty)).collect(Collectors.toSet());
        return sourceList.stream().map(a -> new Bean<>(a, getProperty)).collect(Collectors.toSet())
                .stream().filter(bean -> !beanSet.contains(bean)).map(Bean::getData).collect(Collectors.toList());
    }

    public static <T> List<T> min(List<T> list1, List<T> list2){
        Comparator<List<T>> comparator = Comparator.comparingInt(List::size);
        return BinaryOperator.minBy(comparator).apply(list1, list2);
    }

    public static <T> List<T> max(List<T> list1, List<T> list2){
        Comparator<List<T>> comparator = Comparator.comparingInt(List::size);
        return BinaryOperator.maxBy(comparator).apply(list1, list2);
    }

    private static class Bean<T, K> {

        /**
         * 需要比较的元素
         */
        private final T data;

        /**
         * get方法
         */
        private final Function<T, K>[] getProperty;

        public Bean(T t, Function<T, K>[] getProperty) {
            this.data = t;
            this.getProperty = getProperty;
        }

        public T getData() {
            return data;
        }

        @Override
        public int hashCode() {
            if (ArrayUtil.isEmpty(getProperty)) {
                return data.hashCode();
            }
            // 参考lombok
            int result = 1;
            for (Function<T, K> get : getProperty) {
                K property = get.apply(data);
                result = result * 59 + (property == null ? 43 : property.hashCode());
            }
            return result;
        }

        @Override
        public boolean equals(Object o) {
            if (ArrayUtil.isEmpty(getProperty)) {
                return data.equals(((Bean<T, K>) o).data);
            }
            boolean result = Boolean.TRUE;
            for (Function<T, K> get : getProperty) {
                K property = get.apply(data);
                K property2 = get.apply(((Bean<T, K>) o).data);
                result = result && property.equals(property2);
            }
            return result;
        }
    }

}

四、注意点

例子

    public static void main(String[] args) {
        List<Object> list1 = Arrays.asList(1,9,"2",1.23,new UserRole("骑士", 12, "earth"));
        List<Object> list2 = Arrays.asList(1,10,"5",1.31,1.23,new UserRole("骑士", 12, "earth"));
        System.out.println("查找两个集合中相同的元素");
        System.out.println(findDuplicateElements(list1, list2));
    }

输出如下

将实体类UserRole的@Data改成@Setter、@Getter

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserRole  {
        String roleName;
        Integer level;
        String fiveElements;
    }

重新执行测试用例,输出如下:

可以看到结果中不包含UserRole了,原因是lombok的@Data会重写hashcode和equals方法,实体类是否“”重复“”取决于是否重写了hashCode和equals方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Java代码示例,用于查询两个站点之间的路线信息: ``` import java.util.*; public class RouteFinder { // 定义一个地图,使用邻接矩阵存储站点之间的距离 private int[][] map; // 初始化地图 public RouteFinder(int[][] map) { this.map = map; } // 查找两个站点之间的最短路线,使用Dijkstra算法 public List<Integer> findRoute(int start, int end) { List<Integer> route = new ArrayList<>(); int[] dist = new int[map.length]; boolean[] visited = new boolean[map.length]; int[] prev = new int[map.length]; for (int i = 0; i < map.length; i++) { dist[i] = Integer.MAX_VALUE; visited[i] = false; prev[i] = -1; } dist[start] = 0; for (int i = 0; i < map.length; i++) { int u = getMinDistance(dist, visited); visited[u] = true; for (int v = 0; v < map.length; v++) { if (!visited[v] && map[u][v] != 0 && dist[u] != Integer.MAX_VALUE && dist[u] + map[u][v] < dist[v]) { dist[v] = dist[u] + map[u][v]; prev[v] = u; } } } int current = end; while (current != -1) { route.add(0, current); current = prev[current]; } return route; } // 获取未访问节点距离起点最近的节点 private int getMinDistance(int[] dist, boolean[] visited) { int minDist = Integer.MAX_VALUE; int minIndex = -1; for (int i = 0; i < dist.length; i++) { if (!visited[i] && dist[i] < minDist) { minDist = dist[i]; minIndex = i; } } return minIndex; } public static void main(String[] args) { // 定义一个地图,存储站点之间的距离 int[][] map = { {0, 2, 0, 4, 0}, {2, 0, 3, 0, 0}, {0, 3, 0, 0, 5}, {4, 0, 0, 0, 1}, {0, 0, 5, 1, 0} }; RouteFinder finder = new RouteFinder(map); List<Integer> route = finder.findRoute(0, 4); System.out.println(route); } } ``` 这段代码实现了一个RouteFinder类,其包含一个二维数组map,用于存储站点之间的距离信息。findRoute方法使用Dijkstra算法来查找两个站点之间的最短路线,并返回一个List对象,包含经过的站点的编号。在main方法,我们创建了一个RouteFinder对象,并使用它来查找从站点0到站点4的最短路线。输出结果为[0, 1,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值