All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.centit.support.algorithm.CollectionsOpt Maven / Gradle / Ivy

There is a newer version: 5.3.2302
Show newest version
package com.centit.support.algorithm;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.centit.support.common.TreeNode;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;

/**
 * 一些通用的算法,这些算法都和具体的业务数据结构解耦
 * 1. sortAsTree* 将list按照树形结构进行排序,这个方式是这个类最重要的一个方法,也是这个类存在的一个原因。
 * 2. compareTwoList 比较两个list,将他们相同的、删除的、新增的分别找出来,
 * 刚好对应sql的 update、delete和insert操作。
 * 3. listToArray 和 arrayToList 通过反射的方式简化了传入的参数。
 * 4. remove* 一组对集合元素清理操作。
 * 5. moveListItem 和 changeListItem ,前者为移动元素位置两个元素之间的所有item位置都有变化,
 * 后者为仅仅交换两个元素的位置
 * 6. clone* 复制集合。
 * 7. storedAsTree、treeToJSONArray 对属性结构的存储或者序列化。
 *
 * @author codefan
 * @version 2.2.5
 */
@SuppressWarnings("unused")
public abstract class CollectionsOpt {

    public CollectionsOpt() {
        throw new IllegalAccessError("Utility class");
    }

    /**
     * 移动List一个对象到新的位置
     *
     * @param   泛型类型
     * @param list 输入列表
     * @param item 位置1
     * @param pos  位置2
     */
    public static  void moveListItem(List list, int item, int pos) {
        if (item == pos || item < 0 || pos < 0 || item >= list.size() || pos >= list.size())
            return;
        /*T tmp = list.remove(item);
        list.add(pos, tmp);    */
        if (item > pos) {
            T tmp = list.get(item);
            for (int i = item; i > pos; i--)
                list.set(i, list.get(i - 1));
            list.set(pos, tmp);
        } else {
            T tmp = list.get(item);
            for (int i = item; i < pos; i++)
                list.set(i, list.get(i + 1));
            list.set(pos, tmp);
        }
    }

    /**
     * 交换List中两个对象的位置
     *
     * @param   泛型类型
     * @param list 输入列表
     * @param p1   位置1
     * @param p2   位置2
     */
    public static  void changeListItem(List list, int p1, int p2) {
        if (p1 == p2)
            return;
        Collections.swap(list, p1, p2);
        /*T tmp = list.get(p1);
        list.set(p1, list.get(p2));
        list.set(p2, tmp);    */
    }

    public static  ParentChild mapParentANdChild(
        Function pkExtractor,
        Function parentPkExtractor) {
        //Objects.requireNonNull(parentExtractor);
        //Objects.requireNonNull(childExtractor);
        return (p, c) ->
            GeneralAlgorithm.equals(pkExtractor.apply(p), parentPkExtractor.apply(c));
    }

    /**
     * 将数组结构按照树形展示的形式进行排序,将所有孩子元素放到父元素的下面
     * 深度优先的排序
     *
     * @param   泛型类型
     * @param list 输入列表
     * @param c    对比接口
     */
    public static  void sortAsTree(List list, ParentChild c) {
        int n = list.size();
        if (n < 2)
            return;
        //sorted 已经排序好的数量
        int sortedInd = 0;
        int[] parentInds = new int[n];
        while (sortedInd < n - 1) {
            // 找到所有的根节点
            int parentInd = -1;
            for (int i = sortedInd; i < n; i++) {
                boolean isParent = true;
                for (int j = sortedInd; j < n; j++) {
                    if (i != j && c.parentAndChild(list.get(j), list.get(i))) {
                        isParent = false;
                        break;
                    }
                }
                if (isParent) {
                    parentInd = i;
                    break;
                }
            }
            if (parentInd == -1)
                break;

            moveListItem(list, parentInd, sortedInd);
            parentInds[0] = sortedInd;
            sortedInd++;
            int pathDeep = 1;
            while (pathDeep > 0) {
                int newInsert = 0;
                for (int i = sortedInd; i < n; i++) {
                    if (c.parentAndChild(list.get(parentInds[pathDeep - 1]), list.get(i))) {
                        moveListItem(list, i, sortedInd);
                        parentInds[pathDeep] = sortedInd;
                        pathDeep++;
                        sortedInd++;
                        newInsert++;
                    }
                }
                if (newInsert == 0) {
                    pathDeep--;
                }
            }
            // 查找根节点的所有子元素
            //sortedInd = sortAsTreePiece(list,c,sortedInd);
        }
    }

    /**
     * 将数组结构按照树形展示的形式进行排序,将所有孩子元素放到父元素的下面
     * 深度优先的排序
     *
     * @param list              输入列表
     * @param pkExtractor       父对象 获取 自己的主键
     * @param parentPkExtractor 子对象 获取 父对象主键
     * @param                泛型类型
     * @param                主键类型
     */
    public static  void sortAsTree(List list, Function pkExtractor,
                                         Function parentPkExtractor) {
        CollectionsOpt.sortAsTree(list,
            CollectionsOpt.mapParentANdChild(pkExtractor, parentPkExtractor));
    }

    /**
     * 对排序好的树形数组结构 找到JQueryTree要的Indexes
     *
     * @param   泛型类型
     * @param list 输入列表
     * @param c    对比接口
     * @return 排序号的树的索引
     */
    public static  List makeJqueryTreeIndex(List list, ParentChild c) {
        List indexes = new ArrayList();
        int n = list.size();
        for (int i = 0; i < n; i++) {
            int ind = 0;
            for (int j = 0; j < i; j++) {
                if (c.parentAndChild(list.get(j), list.get(i))) {
                    ind = j + 1;
                    break;
                }
            }
            indexes.add(ind);
        }
        return indexes;
    }

    /**
     * 移除List中的所有null对象
     *
     * @param   泛型类型
     * @param list 输入列表
     * @return 输出列表
     */
    public static  List removeNullItem(List list) {
        if (list == null || list.size() < 1)
            return null;
        List retList = new ArrayList<>(list.size());
        for (T t : list) {
            if (t != null)
                retList.add(t);
        }
        return retList;
    }

    /**
     * 移除List中的所有null对象
     *
     * @param   泛型类型
     * @param list 输入数组
     * @return 输出数组
     */
    public static  T[] removeNullItem(T[] list) {

        if (list == null || list.length < 1)
            return null;
        int notNullItemPos = -1, size = 0;
        for (int i = 0; i < list.length; i++) {
            if (list[i] != null) {
                size++;
                notNullItemPos = i;
            }
        }
        if (notNullItemPos < 0) {
            return null;
        }
        @SuppressWarnings("unchecked")
        T[] ta = (T[]) Array.newInstance(list[notNullItemPos].getClass(), size);
        size = 0;
        for (int i = 0; i < list.length; i++) {
            if (list[i] != null) {
                ta[size] = list[i];
                size++;
            }
        }
        return ta;
    }

    /**
     * 移除String List中的所有 Blank 对象
     *
     * @param list 输入字符串列表
     * @return 输出字符串列表
     */
    public static List removeBlankString(List list) {
        if (list == null || list.size() < 1)
            return null;
        List retList = new ArrayList();
        for (String t : list) {
            if (StringUtils.isNoneBlank(t))
                retList.add(t);
        }
        return retList;
    }

    /**
     * 移除List中的所有null对象
     *
     * @param list 输入字符串数组
     * @return 输出字符串数组
     */
    public static String[] removeBlankString(String[] list) {
        if (list == null || list.length < 1)
            return null;
        int notNullItemPos = -1, size = 0;
        for (int i = 0; i < list.length; i++) {
            if (StringUtils.isNoneBlank(list[i])) {
                size++;
                notNullItemPos = i;
            }
        }
        if (notNullItemPos < 0) {
            return null;
        }
        String[] ta = new String[size];
        size = 0;
        for (int i = 0; i < list.length; i++) {
            if (StringUtils.isNoneBlank(list[i])) {
                ta[size] = list[i];
                size++;
            }
        }
        return ta;
    }

    /**
     * 将TreeList转换为JSONArray
     *
     * @param                   泛型类型
     * @param treeList             必须是已经通过 sortAsTree 排序好的list
     * @param c                    比较算法,需要实现接口 CollectionsOpt.ParentChild T
     * @param childrenPropertyName 为孩子的 属性名
     * @return JSONArray
     */
    public static  JSONArray treeToJSONArray
    (List treeList, ParentChild c, String childrenPropertyName) {
        JSONArray jsonTree = new JSONArray();
        Stack treePath = new Stack();
        Stack jsonPath = new Stack();
        int pathSum = 0;
        for (T treeNode : treeList) {
            JSONObject jsonNode;
            if (ReflectionOpt.isScalarType(treeNode.getClass())) {
                jsonNode = new JSONObject();
                jsonNode.put("value", StringBaseOpt.objectToString(treeNode));
            } else
                jsonNode = (JSONObject) JSON.toJSON(treeNode);

            while (true) {
                if (pathSum == 0 ||
                    (pathSum > 0 && c.parentAndChild(treePath.peek(), treeNode))) {
                    if (pathSum == 0) {
                        jsonTree.add(jsonNode);
                    } else {
                        JSONObject parentJson = jsonPath.peek();
                        JSONArray children = (JSONArray) parentJson.get(childrenPropertyName);
                        if (children == null)
                            children = new JSONArray();
                        children.add(jsonNode);
                        parentJson.put(childrenPropertyName, children);
                    }
                    treePath.push(treeNode);
                    jsonPath.push(jsonNode);

                    pathSum++;
                    break;
                } else {
                    treePath.pop();
                    jsonPath.pop();
                    pathSum--;
                }
            }
        }
        return jsonTree;
    }

    /**
     * 将列表转换为tree结构的json
     *
     * @param                   泛型类型
     * @param treeList             待排序的List
     * @param c                    比较算法,需要实现接口 CollectionsOpt.ParentChild T
     * @param childrenPropertyName 为孩子的 属性名
     * @return JSONArray
     */
    public static  JSONArray srotAsTreeAndToJSON
    (List treeList, ParentChild c, String childrenPropertyName) {
        sortAsTree(treeList, c);
        return treeToJSONArray(treeList, c, childrenPropertyName);
    }

    /**
     * 将数组结构按照树形展示的形式进行排序,将所有孩子元素放到父元素的下面
     * 深度优先的排序
     *
     * @param   泛型类型
     * @param list 输入数组
     * @param c    对比接口
     * @return 排序号的列表
     */
    public static  List> storedAsTree(List list, ParentChild c) {

        List> treeList = new ArrayList>();
        for (T m : list) {
            treeList.add(new TreeNode(m));
        }
        for (TreeNode cNode : treeList) {
            for (TreeNode pNode : treeList) {
                if (pNode != cNode && c.parentAndChild(pNode.getValue(), cNode.getValue())) {
                    pNode.addChild(cNode);
                    break;
                }
            }
        }
        List> resList = new ArrayList>();
        for (TreeNode node : treeList) {
            if (node.isRoot())
                resList.add(node);
        }
        return resList;
    }

    /**
     * 将TreeList转换为JSONArray
     *
     * @param                   泛型类型
     * @param treeList             需要排序的对象列表 必须是 List
     * @param childrenPropertyName 为孩子的 属性名
     * @return JSONArray
     */
    public static  JSONArray treeToJSONArray
    (List> treeList, String childrenPropertyName) {
        if (treeList == null || treeList.size() == 0)
            return null;

        JSONArray ja = new JSONArray();
        for (TreeNode c : treeList) {
            ja.add(c.toJSONObject(childrenPropertyName));
        }
        return ja;
    }

    /**
     * 将列表转换为tree结构的json
     * 和 srotAsTreeAndToJSON 用不同的算法实现,这个需要额外的空间,用递归实现。
     *
     * @param                   泛型类型
     * @param treeList             待排序的List
     * @param c                    比较算法,需要实现接口 CollectionsOpt.ParentChild T
     * @param childrenPropertyName 为孩子的 属性名
     * @return JSONArray
     */
    public static  JSONArray srotAsTreeAndToJSON2
    (List treeList, ParentChild c, String childrenPropertyName) {

        List> sortTree = storedAsTree(treeList, c);
        return treeToJSONArray(sortTree, childrenPropertyName);
    }

    /*
     * 克隆 一个 list
     */
    public static  List cloneList(Collection souList) {
        if (souList == null) {
            return null;
        }
        ArrayList deslist = new ArrayList<>(souList.size() + 1);
        deslist.addAll(souList);
        return deslist;
    }

    /*
     * 克隆 一个 array
     */
    public static  T[] cloneArray(T[] souList) {
        if (souList == null) {
            return null;
        }
        return souList.clone();
        /*if(souList==null || souList.length==0)
            return null;

        @SuppressWarnings("unchecked")
        T[] ta =(T[]) Array.newInstance(souList[0].getClass(), souList.length);
        for(int i=0;i     泛型类型
     * @param oldList 原始list
     * @param newList 新的list
     * @param compare 为对象T的主键排序对比函数,
     * @return 返回三个list, 第一个是 需要新增的,第二个是 新旧对 他们拥有相同的排序值(主键),第三为新值中没有的,即需要删除的
     * insert T update(old,new) T,T  delete T
     */
    public static  Triple, List>, List>
    compareTwoList(List oldList, List newList, Comparator compare) {
        if (oldList == null || oldList.size() == 0)
            return new ImmutableTriple<>(
                newList, null, null);
        if (newList == null || newList.size() == 0)
            return new ImmutableTriple<>(
                null, null, oldList);
        List souList = cloneList(oldList);
        List desList = cloneList(newList);
        Collections.sort(souList, compare);
        Collections.sort(desList, compare);
        //---------------------------------------
        int i = 0;
        int sl = souList.size();
        int j = 0;
        int dl = desList.size();
        List insertList = new ArrayList<>();
        List delList = new ArrayList<>();
        List> updateList = new ArrayList<>();
        while (i < sl && j < dl) {
            int n = compare.compare(souList.get(i), desList.get(j));
            if (n < 0) {
                delList.add(souList.get(i));
                i++;
            } else if (n == 0) {
                updateList.add(new ImmutablePair<>(souList.get(i), desList.get(j)));
                i++;
                j++;
            } else /*if(n>0)*/ {
                insertList.add(desList.get(j));
                j++;
            }
        }

        while (i < sl) {
            delList.add(souList.get(i));
            i++;
        }

        while (j < dl) {
            insertList.add(desList.get(j));
            j++;
        }

        return new ImmutableTriple<>(insertList, updateList, delList);
    }

    /**
     * 将list(Collection 所以 set也可以) 转换为数组, list.toArray(T[]) 感觉不太好用,要new一个接受的数组对象
     *
     * @param        类型
     * @param listObj   Collection 对象 可以是list 也可以是 set
     * @param classType T 的类型
     * @return T[] 数组
     */
    public static  T[] listToArray(Collection listObj, Class classType) {
        if (listObj == null || listObj.size() == 0)
            return null;
        @SuppressWarnings("unchecked")
        T[] ta = (T[]) Array.newInstance(classType, listObj.size());
        return listObj.toArray(ta);
    }

    /**
     * 将list(Collection 所以 set也可以) 转换为数组, list.toArray(T[]) 感觉不太好用,要new一个接受的数组对象
     *
     * @param listObj Collection 对象 可以是list 也可以是 set
     * @param      类型
     * @return 数组
     * 注意,如果这个 T 是一个 接口,并且 Collection 中的内容是这个接口的不同实现,这个方法将抛异常,
     * 这时候需要调用   <T> T[] listToArray(Collection<T> listObj, Class<T> classType)其中 classType 传入接口类
     */
    public static  T[] listToArray(Collection listObj) {
        if (listObj == null || listObj.size() == 0)
            return null;
        @SuppressWarnings("unchecked")
        T[] ta = (T[]) Array.newInstance(listObj.iterator().next().getClass(), listObj.size());

        return listObj.toArray(ta);
        /*for(int i=0;i List arrayToList(T[] arrayObj) {
        if (arrayObj == null || arrayObj.length == 0)
            return null;
        List listObj = new ArrayList<>(arrayObj.length);
        Collections.addAll(listObj, arrayObj);
        return listObj;
    }

    /**
     * 参数必须是 string object string object ....
     *
     * @param objs 参数必须是 string object string object ....
     * @return Map < String,Object >
     */
    public static Map createHashMap(Object... objs) {
        if (objs == null || objs.length < 2)
            return null;
        Map paramsMap = new HashMap<>(objs.length);
        for (int i = 0; i < objs.length / 2; i++) {
            paramsMap.put(String.valueOf(objs[i * 2]), objs[i * 2 + 1]);
        }
        return paramsMap;
    }

    public static  Map createHashMap(String[] keys, T[] values) {
        if (keys == null || values == null)
            return null;
        int len = Math.min(keys.length, values.length);
        Map paramsMap = new HashMap<>(len + 1);
        for (int i = 0; i < len; i++) {
            paramsMap.put(keys[i], values[i]);
        }
        return paramsMap;
    }

    public static  HashMap cloneHashMap(Map souMap) {
        if (souMap == null) {
            return null;
        }
        HashMap paramsMap = new HashMap<>(souMap.size() + 1);
        paramsMap.putAll(souMap);
        //paramsMap.clone()
        return paramsMap;
    }

    public static  Map unionTwoMap(Map map1, Map map2) {
        Map paramsMap = new HashMap<>(map1.size() + map2.size() + 2);
        paramsMap.putAll(map2);
        paramsMap.putAll(map1);
        return paramsMap;
    }

    /**
     * @param objs 参数类型需要一致
     * @param   参数类型
     * @return List < T >
     */
    @SafeVarargs
    public static  List createList(T... objs) {
        if (objs == null)
            return null;
        return Arrays.asList(objs);
    }

    /**
     * 这个按道理可以同 stream来处理, 但是类型转换不太好弄
     * 获取一个list中的所有对象的一个属性,并组成一个新的数组
     * @param list 数组
     * @param propExtractor 对象方法
     * @param  数组类型
     * @param  属性类型
     * @return 属性列表
     */
    public static  List extraListProperties(List list, Function propExtractor) {
        if(list == null){
            return null;
        }
        //list.stream().map(propExtractor).toArray() object[]
        List uList = new ArrayList<>(list.size());
        for(T t : list){
            uList.add(propExtractor.apply(t));
        }
        return uList;
    }

    /*public static  U[] extraArrayProperties(T [] array, Function propExtractor) {
        if(array == null){
            return null;
        }
        U[] uList = (U[]) Array.newInstance(Object.class, array.length);
        int i=0;
        for(T t : array){
            uList[i++] = propExtractor.apply(t);
        }
        return uList;
    }*/

    public static  HashSet cloneSet(Collection souCollection) {
        if (souCollection == null) {
            return null;
        }
        HashSet paramsSet = new HashSet<>(souCollection.size() + 1);
        paramsSet.addAll(souCollection);
        //paramsSet.clone()
        return paramsSet;
    }

    /**
     * @param objs 参数类型需要一致
     * @param   参数类型
     * @return HashSet < T >
     */
    @SafeVarargs
    public static  HashSet createHashSet(T... objs) {
        if (objs == null)
            return null;
        HashSet paramsSet = new HashSet<>(objs.length * 2 + 1);
        Collections.addAll(paramsSet, objs);
        return paramsSet;
    }

    @SuppressWarnings("unchecked")
    public static  T unmodifiableObject(T obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof List) {
            return (T) Collections.unmodifiableList((List) obj);
        }
        if (obj instanceof Map) {
            return (T) Collections.unmodifiableMap((Map) obj);
        }
        if (obj instanceof Set) {
            return (T) Collections.unmodifiableSet((Set) obj);
        }
        if (obj instanceof Collection) {
            return (T) Collections.unmodifiableCollection((Collection) obj);
        }
        return obj;
    }

    public static Map objectToMap(Object object) {
        if (object instanceof Map) {
            return (Map) object;
        }
        if (ReflectionOpt.isScalarType(object.getClass())) {
            return CollectionsOpt.createHashMap("scalar", object);
        }
        if (object.getClass().isArray()) {
            int len = Array.getLength(object);
            HashMap map = new HashMap<>(len * 5 / 4 + 1);
            for (int i = 0; i < len; i++) {
                map.put(String.valueOf(i), Array.get(object, i));
            }
            return map;
        }
        if (object instanceof Collection) {
            HashMap map = new HashMap<>();
            int i = 0;
            for (Object po : (Collection) object) {
                map.put(String.valueOf(i++), po);
            }
            return map;
        }
        Object obj = JSON.toJSON(object);
        if (obj instanceof JSONObject) {
            return (JSONObject) obj;
        }
        return CollectionsOpt.createHashMap("data", object);
    }

    public static Map objectMapToStringMap(Map objectMap) {
        if(objectMap==null){
            return null;
        }
        Map stringMap = new HashMap<>(objectMap.size());
        for(Map.Entry ent : objectMap.entrySet()){
            stringMap.put(StringBaseOpt.objectToString(ent.getKey()),
                StringBaseOpt.objectToString(ent.getValue()));
        }
        return stringMap;
    }

    public static  T fetchFirstItem(Collection collection) {
        if (collection == null || collection.isEmpty())
            return null;
        return collection.iterator().next();
    }

    public static  T fetchFirstItem(T[] array) {
        if (array == null || array.length < 1)
            return null;
        return array[0];
    }

    /**
     * 判断两个对象是否是父子关系,用于针对树形展示的数据结构进行排序
     *
     * @author codefan
     * @version $Rev$ 
* $Id$ */ public interface ParentChild { boolean parentAndChild(T p, T c); } }