de.tsl2.nano.collection.CollectionUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.datastructure Show documentation
Show all versions of tsl2.nano.datastructure Show documentation
optimized implementations for trees, collections, arrays, historized input
/*
* Copyright © 2002-2009 Thomas Schneider
* Alle Rechte vorbehalten.
* Weiterverbreitung, Benutzung, Vervielfältigung oder Offenlegung,
* auch auszugsweise, nur mit Genehmigung.
*
* $Id$
*/
package de.tsl2.nano.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.tsl2.nano.core.IPredicate;
import de.tsl2.nano.core.ITransformer;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.BeanAttribute;
import de.tsl2.nano.core.util.ListSet;
import de.tsl2.nano.core.util.ObjectUtil;
import de.tsl2.nano.core.util.StringUtil;
/**
* some transformation und filter methods for collections
*
* @author Thomas Schneider
* @version $Revision$
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class CollectionUtil extends de.tsl2.nano.core.util.CollectionUtil {
// private static final Log LOG = LogFactory.getLog(CollectionUtil.class);
/**
* if both interfaces ({@link List} and {@link Set}) are needed for one instance, the given collection will be
* wrapped into a {@link ListSet}.
*
* @param item type
* @param listOrSet implementation of {@link List} or {@link Set} to be combined in a new instance of
* {@link ListSet}.
* @return new instanceof {@link ListSet}.
*
* TODO: how to create generics expression to define Set or List like: , L extends List>
* with listOrSet ?
*/
public static final ListSet asListSet(Collection listOrSet) {
if (listOrSet instanceof ListSet) {
return (ListSet) listOrSet;
} else {
return new ListSet(listOrSet);
}
}
/**
* delegates to {@link #getTransformedCollection(Collection, String, Class)}.
*/
public static Collection getTransformedCollection(Collection toTransform, final String attributeName) {
return (Collection) getTransformedCollection(toTransform, attributeName, Object.class);
}
/**
* transform a collection.
*
* @param real type of collection items
* @param transformed type of collection items
* @param toTransform original collection
* @param attributeName attribute name to use to get the transformed type
* @return transformed collection
*/
public static Collection getTransformedCollection(Collection toTransform,
final String attributeName,
Class transformedType) {
final ITransformer transformer = new ITransformer() {
BeanAttribute attribute = null;
@Override
public T transform(S arg0) {
if (attribute == null) {
attribute = BeanAttribute.getBeanAttribute(arg0.getClass(), attributeName);
}
return (T) attribute.getValue(arg0);
}
};
return getList(getTransforming(toTransform, transformer).iterator());
}
public static Collection toStringTransformed(Collection toTransform) {
final ITransformer transformer = new ITransformer() {
@Override
public String transform(S arg0) {
return arg0 != null ? arg0.toString() : "";
}
};
return getList(getTransforming(toTransform, transformer).iterator());
}
/**
* @deprecated: use {@link #getFilteringBetween(Iterable, Comparable, Comparable)} or
* {@link #getFilteringBetween(Iterable, Object, Object, boolean)} instead. getFilteredCollection
*
* @param src full collection
* @param predicate filter
* @return filtering collection
*/
public static Collection getFilteredCollection(Iterable src, IPredicate predicate) {
return getList(getFiltering(src, predicate).iterator());
}
/**
* remove
*
* @param collection type
* @param source source collection
* @param attributeName attribute name of type
* @param value value to search to be removed
* @return removed item or null, if remove failed
*/
public static final T remove(Collection source, Class type, String attributeName, Object value) {
final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName);
for (final T t : source) {
if (value.equals(attribute.getValue(t))) {
if (source.remove(t)) {
return t;
} else {
return null;
}
}
}
return null;
}
/**
* finds an entry through bean-reflection
*
* @param collection type
* @param source source collection
* @param attributeName attribute name of type
* @param value value to search to be found
* @return found item or null
*/
public static final T find(Collection source, Class type, String attributeName, Object value) {
final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName);
for (final T t : source) {
if (value.equals(attribute.getValue(t))) {
return t;
}
}
return null;
}
/**
* wrap source collection holding instances of type 'type' into a new collection - holding values given by
* attributeName.
*
* @param source collection item type
* @param source source collection
* @param type source collection type
* @param attributeName attribute of source collection item to get the value as wrapper stored in the new collection
* @return new collection holding wrapped item instances
*/
public static final Collection> wrap(Collection source, Class type, String attributeName) {
final Collection wrapCollection = new ArrayList(source.size());
final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName);
for (final T t : source) {
wrapCollection.add(attribute.getValue(t));
}
return wrapCollection;
}
/**
* iterates through next count elements and returns a new sublist containing them. useful for performance
* optimizations sending statements to a server. if you don't need a transformer you may use List.sublist(..)
* instead.
*
* Example:
*
*
* Collection myEntities = null;
* Iterator<MySearchViewBean> searchIt = akten.iterator();
* ITransformer<MySearchViewBean, Long> toNumbers = new ITransformer<MySearchViewBean, Long>() {
* @Override
* public Long transform(MySearchViewBean arg0) {
* return arg0.getSpecificNumber();
* }
* };
* for (Collection<Long> specNumbers = CollectionUtil.next(searchIt, blockSize, toNumbers); searchIt.hasNext(); specNumbers = CollectionUtil.next(searchIt,
* blockSize,
* toNumbers)) {
* myEntities = myService.getMyEntityBeans(specNumbers);
* ...
* }
*
*
*
* @param element type
* @param elements iterator on each next call this iterator should be the identical instance!
* @param count block size for. will be the size of the returned sub list
* @param transformer (optional) to transform the items of elements to the type T to be filled into the new list.
* @return sublist
*/
public static final Collection next(Iterator elements, int count, ITransformer transformer) {
ArrayList sublist = new ArrayList(count);
for (int i = 0; i < count && elements.hasNext(); i++) {
sublist.add(transformer != null ? transformer.transform(elements.next()) : (T) elements.next());
}
return sublist;
}
/**
* delegates to {@link #getFilteringBetween(Iterable, Comparable, Comparable)}, copying the filtered list.
*/
public static final > Collection getFilteredBetween(Collection src,
final T from,
final T to) {
return getList(getFilteringBetween(src, from, to).iterator());
}
/**
* delegates to {@link #getFilteringBetween(Iterable, Object, Object, boolean)}, copying the filtered list.
*/
public static final Collection getFilteredBetween(Collection src,
final T from,
final T to,
final boolean ignoreCase) {
return getList(getFilteringBetween(src, from, to, ignoreCase).iterator());
}
/**
* getFiltering
*
* @param src collection to filter
* @param filter filter
* @return filtering collection
*/
public static final , T> I getFiltering(I src, IPredicate filter) {
return FilteringIterator.getFilteringIterable(src, filter);
}
/**
* getFiltering
*
* @param src map to filter
* @param filter key filter
* @return filtering map
*/
public static final , S, T extends Comparable> I getFilteringMapKey(I src,
IPredicate filter) {
return FilteringIterator.getFilteringMap(src, filter);
}
/**
* filters the given collection.
*
* Attention: if 'expression' changes afterwards, the collection iterator may change, too! If you do not want that,
* use {@link #getList(Iterator) to create a copy.
*
* @param collection item type
* @param src collection to filter
* @param expression regular expression to be used as filter. the toString() methods of objects will be used to
* match against.
* @return filtered collection
*/
public static final , T> I getFiltering(I src,
final StringBuilder expression) {
return FilteringIterator.getFilteringIterable(src, new IPredicate() {
@Override
public boolean eval(T arg0) {
String arg = arg0 != null ? arg0.toString() : "";
return arg.matches(expression.toString());
}
});
}
/**
* filters the given collection.
*
* Attention: if 'from' or 'to' are mutables and change afterwards, the collection iterator may change, too! If you
* do not want that, use {@link #getList(Iterator)} to create a copy.
*
* @param collection item type
* @param src collection to filter
* @param from minimum object
* @param to maximum object
* @return filtered collection
*/
public static final , T extends Comparable> I getFilteringBetween(I src,
final T from,
final T to) {
if (from == null && to == null) {
return src;
}
final boolean useNull = from == null || to == null;
return FilteringIterator.getFilteringIterable(src, new IPredicate() {
@Override
public boolean eval(T arg) {
return (arg == null && useNull)
|| ((from == null || arg.compareTo(from) >= 0) && (to == null || arg.compareTo(to) <= 0));
}
});
}
/**
* filters the given collection through its string representations.
*
* Attention: if 'from' or 'to' are mutables and change afterwards, the collection iterator may change, too! If you
* do not want that, use {@link #getList(Iterator)} to create a copy.
*
* @param collection item type
* @param src collection to filter
* @param from minimum object
* @param to maximum object
* @return filtered collection
*/
public static final , T> I getFilteringBetween(I src,
final T from,
final T to,
final boolean ignoreCase) {
if (from == null && to == null) {
return src;
}
return FilteringIterator.getFilteringIterable(src, new IPredicate() {
@Override
public boolean eval(T arg0) {
// to be able to reuse the predicate, we can't do the calculations outside (which would be better for the performance)
String sfrom =
from != null && !ObjectUtil.isEmpty(from) ? ignoreCase && from.toString() != null ? from.toString()
.toUpperCase()
: from.toString() : null;
if (StringUtil.STR_ANY.equals(sfrom)) {
sfrom = null;
}
String sto =
to != null && !ObjectUtil.isEmpty(to) ? ignoreCase && to.toString() != null ? to.toString()
.toUpperCase()
: to.toString() : null;
if (StringUtil.STR_ANY.equals(sto)) {
sto = null;
}
boolean useNull = from == null || to == null;
String sarg = arg0 != null ? ignoreCase && arg0.toString() != null ? arg0.toString().toUpperCase()
: arg0.toString() : null;
return (sarg == null && useNull)
|| ((sfrom == null || sarg.compareTo(sfrom) >= 0) && (sto == null || sarg.compareTo(sto) <= 0));
}
});
}
/**
* getTransforming
*
* @param iterable type
* @param iterable content type
* @param src mostly a collection
* @param transformer transformer
* @return proxied iterable giving {@link TransformingIterator} as iterator.
*/
public static final , S, T> I getTransforming(Iterable src,
ITransformer transformer) {
return TransformingIterator.getTransformingIterable(src, transformer);
}
/**
* combines transforming and filtering a collection
*
* @param iterable type
* @param iterable content type
* @param src mostly a collection
* @param transformer transformer
* @param filter filter
* @return filtered and transformed iterable
*/
public static final , S, T> I getTransforming(Iterable src,
ITransformer transformer,
IPredicate filter) {
return TransformingIterator.getTransformingIterable((Iterable) getFiltering((Iterable) src, filter),
transformer);
}
/**
* see {@link MapEntrySet}.
*
* @param m map to wrap into a proxy to combine the both interfaces {@link List} and {@link Map}.
* @return proxy implementing both interfaces through delegation.
*/
public static Set> asEntrySetExtender(final Map m) {
// /**
// * Extender of a maps entry set - used by MapUtil to provide a combination of Collection and Map. workaround in cause of
// * interface naming clash of {@link Collection} and {@link Map} (method remove(Object) with different return types).
// *
// * @author Tom
// * @version $Revision$
// */
// public interface EntrySetExtender {
// /**
// * @return the map behind the entry set
// */
// Map map();
//
// /**
// * overwrite the entryset add method that will throw an unsupported operation exception.
// */
// boolean add(E entry);
// boolean addAll(Collection extends E> c);
// /**
// * creates a new entry using the {@link #map()}. the new entry should be returned.
// */
// Map.Entry addEntry(K key, V value);
// }
// EntrySetExtender entrySetExtender = new EntrySetExtender() {
// PrivateAccessor