zoukankan      html  css  js  c++  java
  • ListUtils的简单集合操作和原理

    1 Maven依赖

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.0</version>
    </dependency>
    

    2 ListUtil实现集合的异或功能

    • 集合A(1,2,3)异或 集合B(2,3,4)等于 (1,4)
    @Test
    public void test1() {
        List<Integer> listA = new ArrayList<>();
        listA.add(1);
        listA.add(2);
        listA.add(3);
    
        List<Integer> listB = new ArrayList<>();
        listB.add(2);
        listB.add(3);
        listB.add(4);
    
        long start = System.currentTimeMillis();
        List<Integer> sub1 = ListUtils.subtract(listA, listB); // list1与list2的差集
        List<Integer> sub2 = ListUtils.subtract(listB, listA); // list2与list1的差集
        List<Integer> union = ListUtils.union(sub1, sub2); // sub1与sub2的并集
        long diff = System.currentTimeMillis() - start;
        log.info("sub1:{}", sub1); // sub1:[1]
        log.info("sub2:{}",sub2);  // sub2:[4]
        log.info("runtime:{}ms,unionList:{}", diff, union);// runtime:5ms, unionList:[1, 4]
    }
    

    3 ListUtil源码

    • ListUtils类
    public class ListUtils {    
        // 依赖HashBag类
        public static <E> List<E> subtract(final List<E> list1, final List<? extends E> list2) {
            final ArrayList<E> result = new ArrayList<E>();
            // 涉及HashBag,下面进行讲解
            final HashBag<E> bag = new HashBag<E>(list2);
            for (final E e : list1) {
                if (!bag.remove(e, 1)) {
                    result.add(e);
                }
            }
            return result;
        }
        
        // List的addAll功能
        public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
            final ArrayList<E> result = new ArrayList<E>(list1);
            result.addAll(list2);
            return result;
        }
    }
    

    4 Bag接口:背包

    • 从出发点(Bag接口)去思考(HashBag类)具体实现中操作的意思
    • 以一个实际生活的例子做解释:一个放球的背包
    public interface Bag<E> extends Collection<E> {
        // 当object为"红",背包中放了多少红球
        int getCount(Object object);
        // 当object为"蓝",往背包放一个蓝球
        boolean add(E object);
        // 当object为"蓝",往背包放nCopies个蓝球
        boolean add(E object, int nCopies);
        // 当object为"红",把所有红球从背包中取出
        boolean remove(Object object);
        // 当object为"红",把nCopies个红球从背包中取出
        boolean remove(Object object, int nCopies);
        // 背包中有哪几种球:如:1个红 2个蓝 -> 红 蓝
        Set<E> uniqueSet();
        // 总共多少球
        int size();
        // ...省略一些接口
    }
    

    5 HashBag源码与Demo

    • 源码
    public class HashBag<E> extends AbstractMapBag<E> implements Serializable {
       
        public HashBag() {
            super(new HashMap<E, MutableInteger>());
        }
    
        public HashBag(final Collection<? extends E> coll) {
            this();
            super.addAll(coll); // AbstractMapBag的addAll方法
        }
    }
    
    // 内部由一个Map实现
    public abstract class AbstractMapBag<E> implements Bag<E> {
    	/** 用一个Map来放球,key为球,value为数量 */
        private transient Map<E, MutableInteger> map;
        /** 背包有多少球 */
        private int size;
        /** fail fast iterators的安全机制 */
        private transient int modCount;
        /** 有哪几种球的 */
        private transient Set<E> uniqueSet;
    	
        public boolean add(final E object) {
            return add(object, 1);
        }
        
        // 很简单:如果map包含object,则取出value,并加上nCopies;不包含就新建即可。
        public boolean add(final E object, final int nCopies) {
            modCount++;
            if (nCopies > 0) {
                final MutableInteger mut = map.get(object);
                size += nCopies;
                if (mut == null) {
                    map.put(object, new MutableInteger(nCopies));
                    return true;
                }
                mut.value += nCopies;
                return false;
            }
            return false;
        }
        
        // 遍历删除
        public boolean addAll(final Collection<? extends E> coll) {
            boolean changed = false;
            final Iterator<? extends E> i = coll.iterator();
            while (i.hasNext()) {
                final boolean added = add(i.next());
                changed = changed || added;
            }
            return changed;
        }
        
        public boolean remove(final Object object, final int nCopies) {
            final MutableInteger mut = map.get(object);
            if (mut == null)   return false; // 不包含该object则返回false
            if (nCopies <= 0)  return false;
            modCount++;
            if (nCopies < mut.value) { // 如果背包中的数量比删除的数量多则相减
                mut.value -= nCopies;
                size -= nCopies;
            } else { // 如果背包中的数量比删除的数量少则直接删完
                map.remove(object);
                size -= mut.value;
            }
            return true;
        }
        
        // 集合类的toString都需要用到StringBuilder进行append,这样可以提升性能
        public String toString() {
            if (size() == 0) {
                return "[]";
            }
            final StringBuilder buf = new StringBuilder();
            buf.append('[');
            final Iterator<E> it = uniqueSet().iterator();
            while (it.hasNext()) {
                final Object current = it.next();
                final int count = getCount(current);
                buf.append(count);
                buf.append(':');
                buf.append(current);
                if (it.hasNext()) {
                    buf.append(',');
                }
            }
            buf.append(']');
            return buf.toString();
        }
        
        public int getCount(final Object object) {
            final MutableInteger count = map.get(object);
            return count == null ? 0 : count.value;
        }
    
    }
    
    • demo
    @Slf4j // lombok
    public class Main {
        public static void main(String[] args) {
            HashBag<Integer> bag = new HashBag<>();
            bag.add(1);
            bag.add(2);
            bag.add(3);
    
            System.out.println(bag); // [1:1,1:2,1:3] 第一个值为出现次数,第二个value值
            boolean remove2 = bag.remove(2, 1); // 删除2值1次,发现有并删除返回true
            boolean remove4 = bag.remove(4, 1); // 删除4值1次,发现没有返回false
            // remove2:true remove4:false
            log.info("remove2:{} remove4:{}",remove2,remove4);
            System.out.println(bag); // [1:1,1:3]
        }
    }
    

    6 HashCode重写

    • 设计Hash的容器类都需要重写equals方法和hashCode方法来实现自己希望的逻辑,如:HashBag、HashSet或者希望自定义对象作为HashMap的值
    public class Main {
        public static void main(String[] args) {
            Student student1 = new Student("andy", 11,99.5);
            Student student2 = new Student("andy", 11,99.5);
            System.out.println(student1.equals(student2)); // true
    
            Set<Student> set = new HashSet<>();
            set.add(student1);
            set.add(student2);
            System.out.println(set.size()); // 1
        }
    
        @Getter
        @Setter
        static class Student {
            private String name;
            private int age;
            private double score;
    
            public Student(String name, int age,double score) {
                this.name = name;
                this.age = age;
                this.score = score;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj == this) return true;
                if (obj.getClass() != this.getClass()) return false;
                Student student = (Student) obj;
                return student.name.equals(this.name)
                        && student.age == this.age
                        && student.score == this.score;
            }
    
            @Override
            public int hashCode() {
                int hash = 17;
                hash = hash * 31 + name.hashCode();
                hash = hash * 31 + age;
                hash = hash * 31 + Double.valueOf(score).hashCode();
                return hash;
            }
        }
    }
    
    • 注意:lombok的@Data注解会自动帮你重写equals和hashCode方法,不需要时请不要使用@Data注解,避免造成不必要的麻烦
  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9810854.html
Copyright © 2011-2022 走看看