org.dbflute.util.DfCollectionUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dbflute-runtime Show documentation
Show all versions of dbflute-runtime Show documentation
The runtime library of DBFlute
/*
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.dbflute.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author jflute
* @since 0.9.4 (2009/03/20 Friday)
*/
public class DfCollectionUtil {
// ===================================================================================
// Definition
// ==========
// Collections's empty collections can be called clear()
// (unmodifiable used before 1.1)
private static final List> EMPTY_LIST = Collections.emptyList();
private static final Map, ?> EMPTY_MAP = Collections.emptyMap();
private static final Set> EMPTY_SET = Collections.emptySet();
// ===================================================================================
// Collection
// ==========
public static Class> findFirstElementType(Collection> collection) {
for (Object object : collection) {
if (object != null) {
return object.getClass();
}
}
return null;
}
public static boolean hasValidElement(Collection> collection) {
for (Object object : collection) {
if (object != null) {
return true;
}
}
return false;
}
// ===================================================================================
// List
// ====
public static ArrayList newArrayList() {
return new ArrayList();
}
public static ArrayList newArrayList(Collection elements) {
final ArrayList list = newArrayListSized(elements.size());
list.addAll(elements);
return list;
}
@SafeVarargs
public static ArrayList newArrayList(ELEMENT... elements) {
final ArrayList list = newArrayListSized(elements.length);
for (ELEMENT element : elements) {
list.add(element);
}
return list;
}
public static ArrayList newArrayListSized(int size) {
return new ArrayList(size);
}
@SuppressWarnings("unchecked")
public static List emptyList() {
return (List) EMPTY_LIST;
}
// -----------------------------------------------------
// Utility
// -------
public static List> splitByLimit(List elementList, int limit) {
final List> valueList = newArrayList();
final int valueSize = elementList.size();
int index = 0;
int remainderSize = valueSize;
do {
final int beginIndex = limit * index;
final int endPoint = beginIndex + limit;
final int endIndex = limit <= remainderSize ? endPoint : valueSize;
final List splitList = newArrayList();
splitList.addAll(elementList.subList(beginIndex, endIndex));
valueList.add(splitList);
remainderSize = valueSize - endIndex;
++index;
} while (remainderSize > 0);
return valueList;
}
// -----------------------------------------------------
// Advance
// -------
public static OrderDiff analyzeOrderDiff(List beforeUniqueList, List afterUniqueList) {
final LinkedHashSet linkedBeforeSet = newLinkedHashSet(beforeUniqueList);
if (beforeUniqueList.size() != linkedBeforeSet.size()) {
String msg = "The argument 'beforeList' should be unique: " + beforeUniqueList;
throw new IllegalArgumentException(msg);
}
final LinkedHashSet linkedAfterSet = newLinkedHashSet(afterUniqueList);
if (afterUniqueList.size() != linkedAfterSet.size()) {
String msg = "The argument 'afterList' should be unique: " + afterUniqueList;
throw new IllegalArgumentException(msg);
}
final ElementDiff elementDiff = analyzeElementDiff(linkedBeforeSet, linkedAfterSet);
final Set addedSet = elementDiff.getAddedSet();
final Set deletedSet = elementDiff.getDeletedSet();
final List beforeRemainingList = newArrayList(beforeUniqueList);
beforeRemainingList.removeAll(deletedSet);
final List afterRemainingList = newArrayList(afterUniqueList);
afterRemainingList.removeAll(addedSet);
if (beforeRemainingList.size() != afterRemainingList.size()) {
String msg = "The beforeRemainingList.size() should be the same as the afterRemainingList's:";
msg = msg + " beforeRemainingList.size()=" + beforeRemainingList.size();
msg = msg + " afterRemainingList.size()=" + afterRemainingList.size();
throw new IllegalStateException(msg);
}
final Map> movedMap = newLinkedHashMap();
doAnalyzeOrderChange(beforeRemainingList, afterRemainingList, movedMap);
for (Entry> entry : movedMap.entrySet()) {
final ELEMENT movedElement = entry.getKey();
final ELEMENT previousElement = entry.getValue().getPreviousElement();
final int movedIndex = afterUniqueList.indexOf(movedElement);
final ELEMENT realPrevious = afterUniqueList.get(movedIndex - 1);
if (!previousElement.equals(realPrevious)) {
entry.getValue().setPreviousElement(realPrevious);
}
}
final OrderDiff orderDiff = new OrderDiff();
orderDiff.setMovedMap(movedMap);
return orderDiff;
}
protected static void doAnalyzeOrderChange(List beforeRemainingList, List afterRemainingList,
Map> movedMap) {
ELEMENT movedElement = null;
ELEMENT previousElement = null;
for (int i = 0; i < beforeRemainingList.size(); i++) {
final ELEMENT beforeElement = beforeRemainingList.get(i);
final int afterIndex = afterRemainingList.indexOf(beforeElement);
if (i == afterIndex) { // no change
continue;
}
// changed
movedElement = beforeElement;
previousElement = afterRemainingList.get(afterIndex - 1);
break;
}
if (movedElement != null) {
final OrderDiffDetail diffResult = new OrderDiffDetail();
diffResult.setMovedElement(movedElement);
diffResult.setPreviousElement(previousElement);
movedMap.put(movedElement, diffResult);
final List movedList = moveElementToIndex(beforeRemainingList, movedElement, previousElement);
doAnalyzeOrderChange(movedList, afterRemainingList, movedMap); // recursive call
}
}
public static class OrderDiff {
protected Map> _movedMap;
public Map> getMovedMap() {
return _movedMap;
}
public void setMovedMap(Map> movedMap) {
this._movedMap = movedMap;
}
}
public static class OrderDiffDetail {
protected ELEMENT _movedElement;
protected ELEMENT _previousElement;
public ELEMENT getMovedElement() {
return _movedElement;
}
public void setMovedElement(ELEMENT movedElement) {
this._movedElement = movedElement;
}
public ELEMENT getPreviousElement() {
return _previousElement;
}
public void setPreviousElement(ELEMENT previousElement) {
this._previousElement = previousElement;
}
}
public static List moveElementToIndex(List list, ELEMENT fromElement, ELEMENT toElement) {
assertObjectNotNull("list", list);
final int fromIndex = list.indexOf(fromElement);
final int toIndex = list.indexOf(toElement);
return moveElementToIndex(list, fromIndex, toIndex);
}
public static List moveElementToIndex(List list, int fromIndex, int toIndex) {
assertObjectNotNull("list", list);
if (fromIndex == toIndex) {
String msg = "The argument 'fromIndex' and 'toIndex' should not be same:";
msg = msg + " fromIndex=" + fromIndex + " toIndex" + toIndex;
throw new IllegalArgumentException(msg);
}
if (fromIndex < 0 || toIndex < 0) {
String msg = "The argument 'fromIndex' and 'toIndex' should not be minus:";
msg = msg + " fromIndex=" + fromIndex + " toIndex" + toIndex;
throw new IllegalArgumentException(msg);
}
final boolean fromLess = fromIndex < toIndex;
final List movedList = new ArrayList();
final int firstIndex = fromLess ? fromIndex : toIndex;
final int secondIndex = !fromLess ? fromIndex : toIndex;
final List first = list.subList(0, firstIndex);
final ELEMENT element = list.get(fromIndex);
final int adjustmentIndex = fromLess ? 1 : 0;
final List middle = list.subList(firstIndex + adjustmentIndex, secondIndex + adjustmentIndex);
final List last = list.subList(secondIndex + 1, list.size());
movedList.addAll(first);
if (!fromLess) {
movedList.add(element);
}
movedList.addAll(middle);
if (fromLess) {
movedList.add(element);
}
movedList.addAll(last);
return movedList;
}
// -----------------------------------------------------
// Array
// -----
public static List toListFromArray(Object ary) {
final int len = Array.getLength(ary);
final List list = new ArrayList(len);
for (int i = 0; i < len; i++) {
@SuppressWarnings("unchecked")
final ELEMENT element = (ELEMENT) Array.get(ary, i);
list.add(element);
}
return list;
}
// ===================================================================================
// Map
// ===
public static HashMap newHashMap() {
return new HashMap();
}
public static HashMap newHashMap(Map map) {
return new HashMap(map);
}
public static HashMap newHashMap(KEY key, VALUE value) {
final HashMap map = newHashMapSized(1);
map.put(key, value);
return map;
}
public static HashMap newHashMap(KEY key1, VALUE value1, KEY key2, VALUE value2) {
final HashMap map = newHashMapSized(2);
map.put(key1, value1);
map.put(key2, value2);
return map;
}
public static HashMap newHashMapSized(int size) {
return new HashMap(size);
}
public static LinkedHashMap newLinkedHashMap() {
return new LinkedHashMap();
}
public static LinkedHashMap newLinkedHashMap(Map map) {
return new LinkedHashMap(map);
}
public static LinkedHashMap newLinkedHashMap(KEY key, VALUE value) {
final LinkedHashMap map = newLinkedHashMapSized(1);
map.put(key, value);
return map;
}
public static LinkedHashMap newLinkedHashMap(KEY key1, VALUE value1, KEY key2, VALUE value2) {
final LinkedHashMap map = newLinkedHashMapSized(2);
map.put(key1, value1);
map.put(key2, value2);
return map;
}
public static LinkedHashMap newLinkedHashMapSized(int size) {
return new LinkedHashMap(size);
}
public static ConcurrentHashMap newConcurrentHashMap() {
return new ConcurrentHashMap();
}
public static ConcurrentHashMap newConcurrentHashMap(Map map) {
return new ConcurrentHashMap(map);
}
public static ConcurrentHashMap newConcurrentHashMap(KEY key, VALUE value) {
final ConcurrentHashMap map = newConcurrentHashMapSized(1);
map.put(key, value);
return map;
}
public static ConcurrentHashMap newConcurrentHashMap(KEY key1, VALUE value1, KEY key2, VALUE value2) {
final ConcurrentHashMap map = newConcurrentHashMapSized(2);
map.put(key1, value1);
map.put(key2, value2);
return map;
}
public static ConcurrentHashMap newConcurrentHashMapSized(int size) {
return new ConcurrentHashMap(size);
}
@SuppressWarnings("unchecked")
public static Map emptyMap() {
return (Map) EMPTY_MAP;
}
// ===================================================================================
// Set
// ===
public static HashSet newHashSet() {
return new HashSet();
}
public static HashSet newHashSet(Collection elements) {
final HashSet set = newHashSetSized(elements.size());
set.addAll(elements);
return set;
}
@SafeVarargs
public static HashSet newHashSet(ELEMENT... elements) {
final HashSet set = newHashSetSized(elements.length);
for (ELEMENT element : elements) {
set.add(element);
}
return set;
}
public static HashSet newHashSetSized(int size) {
return new HashSet(size);
}
public static LinkedHashSet newLinkedHashSet() {
return new LinkedHashSet();
}
public static LinkedHashSet newLinkedHashSet(Collection elements) {
final LinkedHashSet set = newLinkedHashSetSized(elements.size());
set.addAll(elements);
return set;
}
@SafeVarargs
public static LinkedHashSet newLinkedHashSet(ELEMENT... elements) {
final LinkedHashSet set = newLinkedHashSetSized(elements.length);
for (ELEMENT element : elements) {
set.add(element);
}
return set;
}
public static LinkedHashSet newLinkedHashSetSized(int size) {
return new LinkedHashSet(size);
}
@SuppressWarnings("unchecked")
public static Set emptySet() {
return (Set) EMPTY_SET;
}
// -----------------------------------------------------
// Advance
// -------
public static ElementDiff analyzeElementDiff(Set beforeCol, Set afterCol) {
final Set addedSet = newLinkedHashSet();
final Set deletedSet = newLinkedHashSet();
final Set remainingSet = newLinkedHashSet();
for (ELEMENT beforeElement : beforeCol) {
if (afterCol.contains(beforeElement)) {
remainingSet.add(beforeElement);
} else {
deletedSet.add(beforeElement);
}
}
for (ELEMENT afterElement : afterCol) {
if (!beforeCol.contains(afterElement)) {
addedSet.add(afterElement);
}
}
final ElementDiff elementDiff = new ElementDiff();
elementDiff.setAddedSet(addedSet);
elementDiff.setDeletedSet(deletedSet);
elementDiff.setRemainingSet(remainingSet);
return elementDiff;
}
public static class ElementDiff {
protected Set _addedSet;
protected Set _deletedSet;
protected Set _remainingSet;
public Set getAddedSet() {
return _addedSet;
}
public void setAddedSet(Set addedSet) {
this._addedSet = addedSet;
}
public Set getDeletedSet() {
return _deletedSet;
}
public void setDeletedSet(Set deletedSet) {
this._deletedSet = deletedSet;
}
public Set getRemainingSet() {
return _remainingSet;
}
public void setRemainingSet(Set remainingSet) {
this._remainingSet = remainingSet;
}
}
// ===================================================================================
// Order
// =====
/**
* Order the unordered list according to specified resources.
* @param The type of element.
* @param The type of ID.
* @param unorderedList The unordered list. (NotNull)
* @param resource The resource of according-to-order. (NotNull)
*/
public static void orderAccordingTo(List unorderedList,
AccordingToOrderResource resource) {
assertObjectNotNull("unorderedList", unorderedList);
if (unorderedList.isEmpty()) {
return;
}
assertObjectNotNull("resource", resource);
final List orderedUniqueIdList = resource.getOrderedUniqueIdList();
assertObjectNotNull("resource.getOrderedUniqueIdList()", orderedUniqueIdList);
if (orderedUniqueIdList.isEmpty()) {
return;
}
final AccordingToOrderIdExtractor idExtractor = resource.getIdExtractor();
assertObjectNotNull("resource.getIdExtractor()", idExtractor);
final Map idIndexMap = new LinkedHashMap();
int index = 0;
for (ID_TYPE id : orderedUniqueIdList) {
if (idIndexMap.containsKey(id)) {
String msg = "The id was duplicated: id=" + id + " orderedUniqueIdList=" + orderedUniqueIdList;
throw new IllegalStateException(msg);
}
idIndexMap.put(id, index);
++index;
}
final Comparator comp = new Comparator() {
public int compare(ELEMENT_TYPE o1, ELEMENT_TYPE o2) {
final ID_TYPE id1 = idExtractor.extractId(o1);
final ID_TYPE id2 = idExtractor.extractId(o2);
assertObjectNotNull("id1 of " + o1, id1);
assertObjectNotNull("id2 of " + o2, id2);
final Integer index1 = idIndexMap.get(id1);
final Integer index2 = idIndexMap.get(id2);
if (index1 != null && index2 != null) {
return index1.compareTo(index2);
}
if (index1 == null && index2 == null) {
return 0;
}
return index1 == null ? 1 : -1;
}
};
Collections.sort(unorderedList, comp);
}
public static interface AccordingToOrderIdExtractor {
/**
* Extract ID from the element instance.
* @param element Element instance. (NotNull)
* @return Extracted ID. (NotNull)
*/
ID_TYPE extractId(ELEMENT_TYPE element);
}
public static class AccordingToOrderResource {
protected List _orderedUniqueIdList;
protected AccordingToOrderIdExtractor _idExtractor;
public AccordingToOrderResource setupResource(List orderedUniqueIdList,
AccordingToOrderIdExtractor idExtractor) {
setOrderedUniqueIdList(orderedUniqueIdList);
setIdExtractor(idExtractor);
return this;
}
public List getOrderedUniqueIdList() {
return _orderedUniqueIdList;
}
public void setOrderedUniqueIdList(List orderedUniqueIdList) {
_orderedUniqueIdList = orderedUniqueIdList;
}
public AccordingToOrderIdExtractor getIdExtractor() {
return _idExtractor;
}
public void setIdExtractor(AccordingToOrderIdExtractor idExtractor) {
_idExtractor = idExtractor;
}
}
// ===================================================================================
// Assert Helper
// =============
protected static void assertObjectNotNull(String variableName, Object value) {
if (variableName == null) {
String msg = "The value should not be null: variableName=null value=" + value;
throw new IllegalArgumentException(msg);
}
if (value == null) {
String msg = "The value should not be null: variableName=" + variableName;
throw new IllegalArgumentException(msg);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy