• 统计两组数据的交集和补集(新旧数据的差异比较算法)遍历一次



    旧数据A = {}
    新数据B = {}

    新增项:B - A = { x | x∈B且x∉A}
    删除项:A - B = { x | x∈A且x∉B}
    共有项:B ∩ A = { x | x∈B且x∈A}

     

    import java.io.BufferedReader;
    import java.io.Closeable;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
    
    public class RecordDiff {
        public static void main(String[] args) {
    
            // 根据新数据对旧数据的改变进行统计:新旧项来自数据库约束为自增长整数的原始键字段,即不重复整数,已升序排序
    
            Integer[] as = new Integer[] { 1, 2, 3, 8, 9, 12 };
            Integer[] bs = new Integer[] { 1, 2, 3, 9, 10, 12, 18, 22 };
            // bs = new Integer[] { 1, 2, 3, 9 };
            System.out.println("旧项:" + Arrays.toString(as));
            System.out.println("新项:" + Arrays.toString(bs));
            System.out.println("====================");
            List<Integer> aList = Arrays.asList(as);// old data
            List<Integer> bList = Arrays.asList(bs);// new data
    
            Diff<Integer> diff1 = Diff.difference(aList, bList);
    
            System.out.println("都有项:" + Arrays.toString(diff1.unionList.toArray()));
            System.out.println("新增项:" + Arrays.toString(diff1.addedList.toArray()));
            System.out.println("删除项:" + Arrays.toString(diff1.removedList.toArray()));
            System.out.println("====================");
    
            List<Integer> fromOnlyList = new ArrayList<Integer>();
            List<Integer> againstOnlyList = new ArrayList<Integer>();
            List<Integer> bothList = new ArrayList<Integer>();
            Diff.diff(aList, bList, fromOnlyList, againstOnlyList, bothList);
            System.out.println("都有项:" + Arrays.toString(bothList.toArray()));
            System.out.println("新增项:" + Arrays.toString(againstOnlyList.toArray()));
            System.out.println("删除项:" + Arrays.toString(fromOnlyList.toArray()));
        }
    
        /**
         * 对两组数据进行差异比较,得出新旧的差异:都有项,新增项,删除项
         * 
         * @author fangss
         *
         * @param <T>
         */
        public static class Diff<T extends Comparable<T>> {
            /** 共有项 */
            List<T> unionList;
            /** 差异项 */
            List<T> addedList, removedList;
    
            /**
             * 
             * @param unionList
             *          接受都有项的结果Buffer
             * @param addedList
             *          接受新增项的结果Buffer
             * @param removedList
             *          接受删除项的结果Buffer
             */
            public Diff(List<T> unionList, List<T> addedList, List<T> removedList) {
                super();
                this.unionList = unionList;
                this.addedList = addedList;
                this.removedList = removedList;
            }
    
            /**
             * 新旧数据列表两个都只遍历一次,适用于数据只能向前滚动一次,如读文件行 <br>
             * A B 6 1 7  2 8  3 9  5 10 . 6 11 . 10 12 16 17 18
             * 
             * @param fromList
             *          必须有序,且升序,一般是旧数据, The List to compare from
             * @param againstList
             *          必须有序,且升序,一般是新数据 A List to compare against
             * @param fromOnlyList
             *          补集
             * @param againstOnlyList
             *          补集
             * @param bothList
             *          交集
             */
            public static <T extends Comparable<T>> void diff(List<T> fromList, List<T> againstList, List<T> fromOnlyList,
                    List<T> againstOnlyList, List<T> bothList) {
    
                // 0 - both, 'f' - from, 'a' - against, 和比较结果一致:一样大小都移动,否则谁小谁移动
                int whoMakeWay = 'b';
                Iterator<T> fromIterator = fromList.iterator();
                Iterator<T> againstIterator = againstList.iterator();
    
                T from = null, against = null;
                while (true) {
                    T fromNext = null;
                    if ('a' != whoMakeWay) {
                        if (hasNextOrExhaustRival(fromIterator, null, againstIterator, againstOnlyList)) {
                            from = fromIterator.next();
                            fromNext = from;
                        } else {
                            return;
                        }
                    }
                    if ('f' != whoMakeWay) {
                        if (hasNextOrExhaustRival(againstIterator, fromNext, fromIterator, fromOnlyList)) {
                            against = againstIterator.next();
                        } else {
                            return;
                        }
                    }
                    // 先两个都判断有下一个,然后再移动,否则先移动有下一个而另一个没有,前一个仅自己有的就丢失一项
                    int cmpResult = from.compareTo(against);
                    // 谁小移动谁,一样就都移动。
                    if (0 == cmpResult) {
                        whoMakeWay = 'b';
                        bothList.add(from);
                    } else if (0 > cmpResult) {
                        // from < against: fromIterator continue until 持平0或超过1
                        whoMakeWay = 'f';
                        fromOnlyList.add(from);
                    } else {
                        // from > against: againstIterator continue until 持平0或超过1
                        whoMakeWay = 'a';
                        againstOnlyList.add(against);
                    }
                }
    
            }
    
            public static <T extends Comparable<T>> boolean hasNextOrExhaustRival(Iterator<T> hasNext, T rivalCurVal,
                    Iterator<T> rival, List<T> list) {
                if (hasNext.hasNext()) {
                    return true;
                }
                if (null != rivalCurVal) {
                    list.add(rivalCurVal);
                }
                while (rival.hasNext()) {
                    list.add(rival.next());
                }
                return false;
            }
    
            /**
             * 新旧数据列表两个遍历可能不只一次
             * 
             * @param newList
             *          必须有序,且升序
             * @param oldList
             *          必须有序,且升序
             * @param unionList
             * @param addedList
             * @param removedList
             */
            private static <T> void innerDifference(List<T> newList, List<T> oldList, List<T> unionList, List<T> addedList,
                    List<T> removedList) {
                for (Iterator<T> iterator = removedList.iterator(); iterator.hasNext();) {
                    T item = iterator.next();
                    if (addedList.contains(item)) {
                        unionList.add(item);
                        iterator.remove();
                        addedList.remove(item);
                    }
                }
            }
    
            /**
             * 新旧数据列表两个遍历可能不只一次
             * 
             * @param newList
             *          新数据,必须有序,且升序
             * @param oldList
             *          旧数据,必须有序,且升序
             * @return
             */
            public static <T extends Comparable<T>> Diff<T> difference(List<T> newList, List<T> oldList) {
                List<T> unionList = new ArrayList<T>();
                List<T> addedList = new ArrayList<T>(oldList);
                List<T> removedList = new ArrayList<T>(newList);
                innerDifference(newList, oldList, unionList, addedList, removedList);
                return new Diff<T>(unionList, addedList, removedList);
            }
    
            /**
             * 新旧数据列表两个遍历可能不只一次
             * 
             * @param cursorList
             *          新数据,必须有序,且升序
             * @param baseList
             *          旧数据,必须有序,且升序
             * @param unionList
             * @param addedList
             * @param removedList
             */
            public static <T extends Comparable<T>> void difference(List<T> cursorList, List<T> baseList, List<T> unionList,
                    List<T> addedList, List<T> removedList) {
                addedList.addAll(cursorList);
                removedList.addAll(baseList);
                innerDifference(cursorList, baseList, unionList, addedList, removedList);
            }
    
        }
    
        public List diff(String aFilePath, String bFilePath, String resultFilePath) throws FileNotFoundException {
            BufferedReader aReader = null, bReader = null;
            String aLine, bLine;
            String delimiter = " ";
            try {
                aReader = new BufferedReader(new FileReader(aFilePath));
                bReader = new BufferedReader(new FileReader(aFilePath));
                if (null != (aLine = aReader.readLine())) {
                }
            } catch (Exception e) {
                // TODO: handle exception
            } finally {
                closeQuietly(aReader);
                closeQuietly(bReader);
                closeQuietly(aReader);
            }
            return null;
        }
    
        public static <T extends Closeable> T closeQuietly(T c) {
            if (null != c) {
                try {
                    c.close();
                } catch (IOException e) {
                    // ALog.d("close", e.getMessage());
                }
            }
            return null;
        }
    }

     如下情况:

            Integer[] as = new Integer[] { 1, 2, 3, 6, 12 };
            Integer[] bs = new Integer[] { 1, 2, 3, 8, 10, 22, 26 };

    输出:

    旧项:[1, 2, 3, 6, 12]
    新项:[1, 2, 3, 8, 10, 22, 26]
    都有项:[1, 2, 3]
    新增项:[8, 10, 26]
    删除项:[6, 12]

    有误,新项有剩余

    当以其中一组进行移动时,这个值都是小于不移动那组中的某个位置的值,设为base

    修改后代码(diff方法):

    /**
         * 新旧数据列表两个都只遍历一次,适用于数据只能向前滚动一次,如读文件行 <br>
         * A B 6 1 7  2 8  3 9  5 10 . 6 11 . 10 12 16 17 18
         * 
         * @param fromList
         *          必须有序,且升序,一般是旧数据, The List to compare from
         * @param againstList
         *          必须有序,且升序,一般是新数据 A List to compare against
         * @param fromOnlyList
         *          补集
         * @param againstOnlyList
         *          补集
         * @param bothList
         *          交集
         */
        public static <T extends Comparable<T>> void diff(List<T> fromList, List<T> againstList, List<T> fromOnlyList,
                List<T> againstOnlyList, List<T> bothList) {
    
            // 0 - both, 'f' - from, 'a' - against, 和比较结果一致:一样大小都移动,否则谁小谁移动
            int whoMakeWay = 'b';
            Iterator<T> fromIterator = fromList.iterator();
            Iterator<T> againstIterator = againstList.iterator();
            // 本次循环的大值,他是不移动那组数据里的值,易知还没入结果集的项,也许为null这时是等于(两个都应该继续移动)时
            T baseBigger = null;
            T from = null, against = null;
            while (true) {
                // 预判能不能移动
                if ('a' != whoMakeWay && !hasNextOrExhaustRival(fromIterator, baseBigger, againstIterator, againstOnlyList)) {// 'f' or // 'b'
                    break;
                }
                if ('f' != whoMakeWay && !hasNextOrExhaustRival(againstIterator, baseBigger, fromIterator, fromOnlyList)) {// 'a' or 'b'
                    break;
                }
                // 真正开始移动
                if ('a' != whoMakeWay) {// 'f' or 'b'
                    from = fromIterator.next();
                }
                if ('f' != whoMakeWay) {// 'a' or 'b'
                    against = againstIterator.next();
                }
    
                int cmpResult = from.compareTo(against);
                // 谁小移动谁,一样就都移动。
                // 入结果集的都是较小值或等值,而大值baseBigger在未来比较时如果小了或等了才入,
                // 故而如果由于某一组数据结束了,就不走以下语句,从而入结果集需要检查这种情况。
                if (0 == cmpResult) {
                    whoMakeWay = 'b';
                    bothList.add(from);
                    baseBigger = null;
                } else if (0 > cmpResult) {
                    // from < against: fromIterator continue until 持平0或超过1
                    if ('f' != whoMakeWay) {
                        whoMakeWay = 'f';
                        baseBigger = against;
                    }
                    fromOnlyList.add(from);
                } else {
                    // from > against: againstIterator continue until 持平0或超过1
                    if ('a' != whoMakeWay) {
                        whoMakeWay = 'a';
                        baseBigger = from;
                    }
                    againstOnlyList.add(against);
                }
            }
        }
    
        /**
         * 如果入参hasNext还有下一项,返回true;否则追加还未入结果集的rivalCurVal以及另一组数据的剩余项到结果集
         * 
         * @param hasNext
         *          带检查是否有下一项
         * @param rivalCurVal
         *          还未入结果集的项
         * @param rival
         *          另一组数据的剩余项开始位置
         * @param list
         *          结果集
         * @return
         */
        public static <T extends Comparable<T>> boolean hasNextOrExhaustRival(Iterator<T> hasNext, T rivalCurVal, Iterator<T> rival,
                List<T> list) {
            if (hasNext.hasNext()) {
                return true;
            }
            if (null != rivalCurVal) {
                list.add(rivalCurVal);
            }
            while (rival.hasNext()) {
                list.add(rival.next());
            }
            return false;
        }

    旧项:[1, 2, 3, 6, 12]
    新项:[1, 2, 3, 8, 10, 22, 26]
    都有项:[1, 2, 3]
    新增项:[8, 10, 22, 26]
    删除项:[6, 12]

        public static <T extends Comparable<T>> void diff(List<T> fromList, List<T> againstList, List<T> fromOnlyList,
                List<T> againstOnlyList, List<T> bothList) {
            Iterator<T> fromIterator = fromList.iterator();
            Iterator<T> againstIterator = againstList.iterator();
            // 本次循环的大值就是对方值(本次循环不移动的那组数据,还未入结果集),如果相等则两者都被设置为null,这也是初始值
            T from = null, against = null;
            while (true) {
                // 预判能不能移动,既然是我该移动,说明我是小值或等值。所以判断有下一个时,除了第一入参其他都是对方相关的参数。
                // 在等于时,即两者都移动,from和against中是不存在未入结果集的数据项,两者应该是null;
                //否则需要考虑未入结果集,即,只有一方移动时却没有下一项而跳出循环,大值没入结果集:
                if (null == from && !hasNextOrExhaustRival(fromIterator, against, againstIterator, againstOnlyList)) {// 'f' or 'b'
                    break;
                }
                if (null == against && !hasNextOrExhaustRival(againstIterator, from, fromIterator, fromOnlyList)) {// 'a' or 'b'
                    break;
                }
    
                // 真正开始移动,获得值
                if (null == from) {// 'f' or 'b'
                    from = fromIterator.next();
                }
                if (null == against) {// 'a' or 'b'
                    against = againstIterator.next();
                }
                int cmpResult = from.compareTo(against);
    
                // 谁小移动谁,一样就都移动。
                // 入结果集的都是较小值或等值,而大值baseBigger在未来比较时如果小了或等了才入,
                // 故而如果由于某一组数据结束了,就不走以下语句,从而入结果集需要检查这种情况。
                if (0 == cmpResult) {
                    bothList.add(from);
                    from = null;
                    against = null;
                } else if (0 > cmpResult) {
                    // from < against: fromIterator continue until 持平0或超过1
                    fromOnlyList.add(from);
                    from = null;
                } else {
                    // from > against: againstIterator continue until 持平0或超过1
                    againstOnlyList.add(against);
                    against = null;
                }
            }
        }

     Diff

            Diff<Integer> diff = new Diff<Integer>() {
    
                @Override
                public int compare(Integer o1, Integer o2) {
                    // TODO Auto-generated method stub
                    return o1.compareTo(o2);
                }
    
                @Override
                public void diff(Integer from, Integer against, int diff) {
                    System.out.println((char) diff + ": " + from + " vs " + against);
                }
            };
            List<Integer> aList = Arrays.asList(new Integer[] { 1, 2, 3, 6, 12 });// old data
            List<Integer> bList = Arrays.asList(new Integer[] { 1, 2, 3, 8, 10, 22, 26 });// new data
            Diff.diff(aList.iterator(), bList.iterator(), diff);

    diff

    /**
         * 
         * @param <T>
         *          项不允许为null
         * @usage <pre>
         * Diff&lt;Integer&gt; diff = new Diff&lt;Integer&gt;() {
         * 
         *     &#064;Override
         *     public int compare(Integer o1, Integer o2) {
         *         // TODO Auto-generated method stub
         *         return o1.compareTo(o2);
         *     }
         * 
         *     &#064;Override
         *     public void diff(Integer from, Integer against, int diff) {
         *         System.out.println((char) diff + &quot;: &quot; + from + &quot; vs &quot; + against);
         *     }
         * };
         * List&lt;Integer&gt; aList = Arrays.asList(new Integer[] { 1, 2, 3, 6, 12 });// old data
         * List&lt;Integer&gt; bList = Arrays.asList(new Integer[] { 1, 2, 3, 8, 10, 22, 26 });// new data
         * Diff.diff(aList.iterator(), bList.iterator(), diff);
         * </pre>
         */
        public static interface Diff<T> extends Comparator<T> {
            public void diff(T from, T against, int diff);
    
            static final int MOVE_FROM = -1;
            static final int MOVE_AGAINST = 1;
            static final int MOVE_FROM_AND_AGAINST = 0;
    
            public static <T> void diff(Iterator<T> fromIterator, Iterator<T> againstIterator, Diff<T> diffcallback) {
                // 本次循环的大值就是对方值(本次循环不移动的那组数据,还未入结果集),如果相等则两者都被设置为null,这也是初始值
                T from = null, against = null;
                int cmpResult = 0;
                while (true) {
                    // 预判能不能移动,既然是我该移动,说明我是小值或等值。所以判断有下一个时,除了第一入参其他都是对方相关的参数。
                    // 在等于时,即两者都移动,from和against中是不存在未入结果集的数据项,两者应该是null;
                    // 否则需要考虑未入结果集,即,只有一方移动时却没有下一项而跳出循环,大值没入结果集:
                    if (MOVE_AGAINST != cmpResult && !fromIterator.hasNext()) {// 'f' or 'b'
                        if (null != against) {
                            diffcallback.diff(null, against, '+');
                        }
                        while (againstIterator.hasNext()) {
                            diffcallback.diff(null, againstIterator.next(), '+');
                        }
                        break;
                    }
                    if (MOVE_FROM != cmpResult && !againstIterator.hasNext()) {// 'a' or 'b'
                        if (null != from) {
                            diffcallback.diff(from, null, '-');
                        }
                        while (fromIterator.hasNext()) {
                            diffcallback.diff(fromIterator.next(), null, '-');
                        }
                        break;
                    }
    
                    // 真正开始移动,获得值
                    if (MOVE_AGAINST != cmpResult) {// 'f' or 'b'
                        from = fromIterator.next();
                    }
                    if (MOVE_FROM != cmpResult) {// 'a' or 'b'
                        against = againstIterator.next();
                    }
                    cmpResult = diffcallback.compare(from, against);
    
                    // 谁小移动谁,一样就都移动。
                    // 入结果集的都是较小值或等值,而大值baseBigger在未来比较时如果小了或等了才入,
                    // 故而如果由于某一组数据结束了,就不走以下语句,从而入结果集需要检查这种情况。
                    if (0 == cmpResult) {
                        diffcallback.diff(from, against, '*');
                        from = null;
                        against = null;
                    } else if (0 > cmpResult) {
                        // from < against: fromIterator continue until 持平0或超过1
                        diffcallback.diff(from, null, '-');
                        from = null;
                    } else {
                        // from > against: againstIterator continue until 持平0或超过1
                        diffcallback.diff(null, against, '+');
                        against = null;
                    }
                }
            }
        }

     迭代相同行为

    /** 类似{@link BufferedReader#readLine}没有判断下一项而是通过null判断,这个类可以实现 Iterator接口,有相同的行为,使用很少 */
        public static abstract class IterateAdapter<T> implements Iterator<T> {
            private boolean hasReadNext;
            /** 跟着游标走的值,调用hasNext和next,保护的成员 */
            public T value;
            protected boolean hasNext;
    
            @Override
            public boolean hasNext() {
                if (!hasReadNext) {
                    value = readNext();
                    hasReadNext = true;
                }
                return hasNext;
            }
    
            /** 真正的,没有下一项需要设置保护的成员 hasNext,因为没有下一项不能单纯靠返回null,如果下一项允许null就不正确了 */
            public abstract T readNext();
    
            @Override
            public T next() {
                if (hasReadNext) {
                    hasReadNext = false;
                    return value;
                } else {
                    value = readNext();
                }
                if (!hasNext) {
                    throw new NoSuchElementException();
                }
                return value;
            }
    
            @Override
            public void remove() {
                throw new UnsupportedOperationException("remove");
            }
        }
    
        /** 使用例子 */
        public static class IterableAdapter<T> extends IterateAdapter<T> {
            private Iterator<T> iterator;
    
            public IterableAdapter(Iterator<T> iterator) {
                this.iterator = iterator;
            }
    
            @Override
            public T readNext() {
                return (hasNext = iterator.hasNext()) ? iterator.next() : null;
            }
        }
  • 相关阅读:
    函数进阶,递归,二分法查找
    内置函数
    IDEA使用maven创建web工程并完善的过程
    后端传入前端的数据的属性名全部为小写的解决方法
    今日总结,复习了很多知识
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ztreeoneServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; 错误的解决方法
    xxx cannot be resolved to a type 的可能的解决方法,mybatis的Example类不存在
    记录一下Spirng Initializr初始化项目的时候pom文件的内容
    使用nacos进行服务注册的配置
    org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing问题的一种解决方法参考
  • 原文地址:https://www.cnblogs.com/Fang3s/p/4762715.html
Copyright © 2020-2023  润新知