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

com.aggrepoint.utils.CollectionUtils Maven / Gradle / Ivy

The newest version!
package com.aggrepoint.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 
 * @author jiangmingyang
 */
public class CollectionUtils {
	public static  T first(Collection entities,
			Function compare) {
		if (entities == null)
			return null;
		for (T t : entities)
			if (compare.apply(t))
				return t;
		return null;
	}

	public static  boolean firstThen(Collection entities,
			Function compare, Consumer then) {
		if (entities == null)
			return false;
		T t = first(entities, compare);
		if (t == null)
			return false;
		then.accept(t);
		return true;
	}

	public static  List toList(Collection entities,
			Function mapper) {
		if (entities == null)
			return null;
		return entities.stream().map(mapper).filter(p -> p != null)
				.collect(Collectors.toList());
	}

	public static  List toList(Collection entities,
			Predicate predicate, Function mapper) {
		if (entities == null)
			return null;
		return entities.stream().filter(predicate).map(mapper)
				.filter(p -> p != null).collect(Collectors.toList());
	}

	public static  Set toSet(Collection entities,
			Function mapper) {
		if (entities == null)
			return null;
		return entities.stream().map(mapper).filter(p -> p != null)
				.collect(Collectors.toSet());
	}

	public static > M toMap(Collection entities,
			Function keyMapper, Supplier supplier) {
		if (entities == null)
			return null;
		return entities.stream().collect(
				Collectors.toMap(keyMapper, Function.identity(), (a, b) -> b,
						supplier));
	}

	public static > M toMap(
			Collection entities, Function keyMapper,
			Function valueMapper, Supplier supplier) {
		if (entities == null)
			return null;
		return entities.stream()
				.collect(
						Collectors.toMap(keyMapper, valueMapper, (a, b) -> b,
								supplier));
	}

	/**
	 * Convert a collection to HashMap, The key is decided by keyMapper, value
	 * is the object in collection
	 * 
	 * @param entities
	 * @param keyMapper
	 * @return
	 */

	public static  HashMap toHashMap(Collection entities,
			Function keyMapper) {
		return toMap(entities, keyMapper, HashMap::new);
	}

	public static  HashMap toHashMap(T[] entities,
			Function keyMapper) {
		return toHashMap(Arrays.asList(entities), keyMapper);
	}

	public static  HashMap toHashMap(Collection entities,
			Function keyMapper, Function valueMapper) {
		return toMap(entities, keyMapper, valueMapper, HashMap::new);
	}

	public static  HashMap toHashMap(T[] entities,
			Function keyMapper, Function valueMapper) {
		return toHashMap(Arrays.asList(entities), keyMapper, valueMapper);
	}

	/**
	 * Convert a collection to Hashtable. The key is decided by keyMapper, value
	 * is the object in collection
	 * 
	 * @param entities
	 * @param keyMapper
	 * @return
	 */
	public static  Hashtable toHashtable(Collection entities,
			Function keyMapper) {
		return toMap(entities, keyMapper, Hashtable::new);
	}

	public static  Hashtable toHashtable(T[] entities,
			Function keyMapper) {
		return toHashtable(Arrays.asList(entities), keyMapper);
	}

	public static  Hashtable toHashtable(Collection entities,
			Function keyMapper, Function valueMapper) {
		return toMap(entities, keyMapper, valueMapper, Hashtable::new);
	}

	public static  Hashtable toHashtable(T[] entities,
			Function keyMapper, Function valueMapper) {
		return toHashtable(Arrays.asList(entities), keyMapper, valueMapper);
	}

	public static > HashMap group(
			Collection entities, Function keyMapper,
			Function valueMapper, Supplier collectionFactory) {
		if (entities == null)
			return null;
		return entities.stream().collect(
				Collectors.groupingBy(
						keyMapper,
						HashMap::new,
						Collectors.mapping(valueMapper,
								Collectors.toCollection(collectionFactory))));
	}

	public static  HashMap> group(
			Collection entities, Function keyMapper,
			Function valueMapper) {
		return group(entities, keyMapper, valueMapper, HashSet::new);
	}

	public static  HashMap> groupAsList(
			Collection entities, Function keyMapper) {
		return group(entities, keyMapper, Function.identity(), ArrayList::new);
	}

	public static  HashMap> groupAsList(
			Collection entities, Function keyMapper,
			Function valueMapper) {
		return group(entities, keyMapper, valueMapper, ArrayList::new);
	}

	public static  HashMap groupJoining(
			Collection entities, Function keyMapper,
			Function valueMapper, String delimiter) {
		if (entities == null)
			return null;
		return entities.stream().collect(
				Collectors.groupingBy(
						keyMapper,
						HashMap::new,
						Collectors.mapping(valueMapper,
								Collectors.joining(delimiter))));
	}

	public static  HashMap> group(T[] entities,
			Function keyMapper, Function valueMapper) {
		return group(Arrays.asList(entities), keyMapper, valueMapper);
	}

	/**
	 * Grouping into 2 levels
	 * 
	 * @param entities
	 * @param keyMapper1
	 * @param keyMapper2
	 * @param valueMapper
	 * @param collectionFactory
	 * @return
	 */
	public static > HashMap> groupTwice(
			Collection entities, Function keyMapper1,
			Function keyMapper2, Function valueMapper,
			Supplier collectionFactory) {
		if (entities == null)
			return null;
		return entities.stream().collect(
				Collectors.groupingBy(keyMapper1, HashMap::new, Collectors
						.groupingBy(keyMapper2, HashMap::new, Collectors
								.mapping(valueMapper, Collectors
										.toCollection(collectionFactory)))));
	}

	/**
	 * Similar to grouping into 2 levels except each unit is not a Collection
	 * but a single object
	 * 
	 * @param entities
	 * @param keyMapper1
	 * @param keyMapper2
	 * @param valueMapper
	 * @return
	 */
	public static  HashMap> matrix(
			Collection entities, Function keyMapper1,
			Function keyMapper2, Function valueMapper) {
		if (entities == null)
			return null;
		return entities.stream().collect(
				Collectors.groupingBy(keyMapper1, HashMap::new, Collectors
						.toMap(keyMapper2, valueMapper, (a, b) -> a,
								HashMap::new)));
	}

	/**
	 * Extract attribute from objects in collection and store them in array and
	 * return.
	 * 
	 * @param entities
	 * @param keyMapper
	 * @param arr
	 * @return
	 */
	public static  K[] toArray(Collection entities,
			Function keyMapper, K[] arr) {
		if (entities == null)
			return null;
		return entities.stream().map(keyMapper).toArray(size -> arr);
	}

	/**
	 * Move an object in List up
	 * 
	 * @param list
	 * @param key
	 * @param keyMapper
	 * @return
	 */
	public static  boolean moveUp(List list, K key,
			Function keyMapper, int n) {
		if (list == null)
			return false;
		ArrayList newList = new ArrayList();
		boolean changed = false;
		for (int i = 0; i < list.size(); i++) {
			T item = list.get(i);

			if (i > 0 && key.equals(keyMapper.apply(item))) {
				int posi = i - n;
				if (posi < 0)
					posi = 0;
				newList.add(posi, item);
				changed = true;
			} else
				newList.add(item);
		}

		if (changed) {
			list.clear();
			list.addAll(newList);
			return true;
		}
		return false;
	}

	public static  boolean moveUp(List list, K key,
			Function keyMapper) {
		return moveUp(list, key, keyMapper, 1);
	}

	/**
	 * Move an object in List down
	 * 
	 * @param list
	 * @param key
	 * @param keyMapper
	 * @return
	 */
	public static  boolean moveDown(List list, K key,
			Function keyMapper, int n) {
		if (list == null)
			return false;
		ArrayList newList = new ArrayList();
		boolean changed = false;
		int start = list.size() - 1;
		for (int i = start; i >= 0; i--) {
			T item = list.get(i);

			if (i != start && key.equals(keyMapper.apply(item))) {
				int posi = n;
				if (newList.size() < posi)
					posi = newList.size();
				newList.add(posi, item);
				changed = true;
			} else
				newList.add(0, item);
		}

		if (changed) {
			list.clear();
			list.addAll(newList);
			return true;
		}
		return false;
	}

	public static  boolean moveDown(List list, K key,
			Function keyMapper) {
		return moveDown(list, key, keyMapper, 1);
	}

	/**
	 * 将列表中id为key的项向前或向后移动n个位置。n为正表示向后移动,n为负表示向前移动。
	 * 
	 * @param list
	 * @param key
	 * @param keyMapper
	 * @param n
	 * @return
	 */
	public static  boolean move(List list, K key,
			Function keyMapper, int n) {
		if (n == 0)
			return false;

		if (n > 0)
			return moveDown(list, key, keyMapper, n);

		return moveUp(list, key, keyMapper, -n);
	}

	/**
	 * 如果before为true则把key移动到ref前面,否则把key移动到ref后面
	 * 
	 * @param list
	 * @param key
	 * @param ref
	 * @param keyMapper
	 * @param before
	 * @return 被移动的元素移动后在列表中的位置,-1表示没有被移动
	 */
	public static  List move(List list, K key, K ref,
			Function keyMapper, boolean before,
			Function orderGet, OrderSetter orderSet, int orderGap) {
		if (key == ref)
			return null;

		// { 找到要移动的项和参考项所在位置
		int keyidx = -1;
		int refidx = -1;
		int idx = 0;

		for (T t : list) {
			K id = keyMapper.apply(t);
			if (id.equals(key))
				keyidx = idx;
			if (id.equals(ref))
				refidx = idx;

			if (keyidx != -1 && refidx != -1)
				break;

			idx++;
		}

		if (keyidx == -1 || refidx == -1)
			return null;
		// }

		// { 拿走要移动的项
		T t = list.remove(keyidx);
		if (refidx >= keyidx)
			refidx--;

		if (!before)
			refidx++;
		// }

		// 放回要移动的项
		list.add(refidx, t);

		// { 设置排序位置
		ArrayList moved = new ArrayList();

		int startOrder = 0;
		if (refidx > 0)
			startOrder = orderGet.apply(list.get(refidx - 1));

		for (int i = refidx + 1; i < list.size(); i++) {
			int order = orderGet.apply(list.get(i));
			if (order - startOrder >= i - refidx + 1) {
				int gap = (order - startOrder) / (i - refidx + 1);
				for (int j = refidx; j < i; j++) {
					T move = list.get(j);

					orderSet.apply(move, startOrder + (j - refidx + 1) * gap);
					moved.add(move);
				}

				return moved;
			}
		}

		for (int i = refidx; i < list.size(); i++) {
			T move = list.get(i);

			orderSet.apply(move, startOrder + (i - refidx + 1) * orderGap);
			moved.add(move);
		}

		return moved;
		// }
	}

	/**
	 * 建立树形结构
	 * 
	 * @param list
	 * @param keyMapper
	 * @param parentKeyMapper
	 * @param childMapper
	 * @return
	 */
	public static  ArrayList buildTree(Collection list,
			Function keyMapper, Function parentKeyMapper,
			Function> childMapper) {
		HashMap map = toHashMap(list, keyMapper);

		ArrayList root = new ArrayList();
		for (T t : list) {
			K key = keyMapper.apply(t);
			K parentKey = parentKeyMapper.apply(t);
			if (parentKey == null || key.equals(parentKey))
				root.add(t);
			else
				childMapper.apply(map.get(parentKey)).add(t);
		}

		return root;
	}

	public static  ArrayList copyTrees(Collection trees,
			Function keyMapper, Function> childMapper,
			Function cloneMapper, Collection toCopy) {
		ArrayList copy = new ArrayList();

		if (toCopy == null)
			return copy;

		for (T node : trees) {
			T copyNode = copyTree(node, keyMapper, childMapper, cloneMapper,
					toCopy);
			if (copyNode != null)
				copy.add(copyNode);
		}

		return copy;
	}

	public static  T copyTree(T node, Function keyMapper,
			Function> childMapper, Function cloneMapper,
			Collection toCopy) {
		if (toCopy == null)
			return null;

		T copy = null;

		Collection children = childMapper.apply(node);
		if (children != null && children.size() > 0) {
			for (T child : children) {
				T childCopy = copyTree(child, keyMapper, childMapper,
						cloneMapper, toCopy);
				if (childCopy != null) {
					if (copy == null)
						copy = cloneMapper.apply(node);
					childMapper.apply(copy).add(childCopy);
				}
			}
		}

		if (copy == null && toCopy.contains(keyMapper.apply(node)))
			copy = cloneMapper.apply(node);

		return copy;
	}

	public static int[] toArray(Collection col) {
		if (col == null)
			return null;
		int[] arr = new int[col.size()];
		int i = 0;
		for (Integer v : col)
			arr[i++] = v.intValue();
		return arr;
	}

	public static  Collection sort(Collection list,
			Function order, boolean asc) {
		if (list == null || order == null)
			return list;

		ArrayList ar = new ArrayList();
		ar.addAll(list);
		ar.sort((p1, p2) -> {
			Number order1 = order.apply(p1);
			Number order2 = order.apply(p2);
			if (order1.doubleValue() > order2.doubleValue())
				return asc ? 1 : -1;
			else if (order1.doubleValue() < order2.doubleValue())
				return asc ? -1 : 1;
			return 0;
		});
		list.clear();
		list.addAll(ar);
		return list;
	}

	public static  Collection sort(Collection list,
			Function order) {
		return sort(list, order, true);
	}

	/**
	 * 用于为Collection中的父对象加载子对象。子对象加载应以父对象的key的集合为条件,父对象中应该有一个集合用于存放子对象。
	 * 
	 * 例如父对象Parent有属性id和集合childs,子对象Child有属性parentId。假设
	 * loader.load()可以根据parentId加载子对象集合,对于类型为List的parents:
	 * 
	 * 
	 * loadChild(parents, Parent::getId, Parent::getChilds, ids -> loader.load(ids),
	 * 		Child::getParentId);
	 * 
*/ public static void loadChildren(Collection list, Function keyMapper, Function> childCollectionMapper, Function, Collection> loader, Function childKeyMapper) { if (list == null || list.size() == 0) return; HashMap map = toHashMap(list, keyMapper); loader.apply(map.keySet()).forEach( p -> childCollectionMapper.apply( map.get(childKeyMapper.apply(p))).add(p)); } /** * list为装有类型为T的对象的集合,称为集合一。用T对象中通过keyGetter获得的key值组成集合,调用 * loader,可以获得类型为S的对象集合,称为集合二。T和S的关系是N对1。把集合一中通过 * keyGetter获得的关键值与集合二中通过loadedKeyGetter获得关键值相同的T和S对象匹配,调用match。 */ public static > X loadNToOne(X list, Function keyGetter, Function, Collection> loader, Function loadedKeyGetter, BiConsumer match) { if (list == null || list.size() == 0) return list; Set keys = toSet(list, keyGetter); if (keys == null || keys.size() == 0) return list; Collection subs = loader.apply(keys); if (subs == null || subs.size() == 0) return list; HashMap map = toHashMap(subs, loadedKeyGetter); for (T item : list) { K key = keyGetter.apply(item); if (key == null) continue; S sub = map.get(key); if (sub == null) continue; match.accept(item, sub); } return list; } /** * list为装有类型为T的对象的集合,称为集合一。用T对象中通过keyGetter获得的key值组成集合,调用 * loader,可以获得类型为S的对象集合,称为集合二。T和S的关系是1对N。把集合一中通过 * keyGetter获得的关键值与集合二中通过loadedKeyGetter获得关键值相同的T和S对象匹配,调用match。 */ public static > X loadOneToN(X list, Function keyGetter, Function, Collection> loader, Function loadedKeyGetter, BiConsumer match) { if (list == null || list.size() == 0) return list; Set keys = toSet(list, keyGetter); if (keys == null || keys.size() == 0) return list; Collection subs = loader.apply(keys); if (subs == null || subs.size() == 0) return list; HashMap map = toHashMap(list, keyGetter); for (S sub : subs) { T item = map.get(loadedKeyGetter.apply(sub)); if (item == null) continue; match.accept(item, sub); } return list; } public static List asList(T obj) { if (obj == null) return null; List list = new ArrayList(); list.add(obj); return list; } /** * 把obj包装为集合,调用function */ public static T callAsCollection(T obj, Consumer> function) { if (obj == null) return null; List list = new ArrayList(); list.add(obj); function.accept(list); return obj; } public static T findOrFirst(Collection list, Function mapper, T toFind) { if (list == null || list.size() == 0) return null; if (toFind != null) for (K k : list) if (mapper.apply(k).equals(toFind)) return toFind; return mapper.apply(list.iterator().next()); } }