I Need a java function which converts from java.util.List to java.util.Set and vice versa, independent of type of objects in the List/Set.
Like List.addAll and Set.addAll?
Most of the class of the java collection framework have a constructor that take a collection of element as a parameter. You should use your prefered implementation ton do the conversion for exameple (with HashSet and ArrayList):
public class MyCollecUtils {
public static <E> Set<E> toSet(List<E> l) {
return new HashSet<E>(l);
}
public static <E> List<E> toSet(Set<E> s) {
return new ArrayList<E>(s);
}
}
public static <E> Set<E> getSetForList(List<E> lst){
return new HashSet<E>(lst);//assuming you don't care for duplicate entry scenario :)
}
public static <E> List<E> getListForSet(Set<E> set){
return new ArrayList<E>(set);// You can select any implementation of List depending on your scenario
}
Instead of one function you can have two function to implement this functionality:
// Set to List
public List setToList(Set set) {
return new ArrayList(set);
}
// List to Set
public Set listToSet(List list) {
return new HashSet(list);
}
In a single function:
public Collection convertSetList(Collection obj) {
if (obj instanceof java.util.List) {
return new HashSet((List)obj);
} else if(obj instanceof java.util.Set) {
return new ArrayList((Set)obj);
}
return null;
}
Example: (updated)
public class Main {
public static void main(String[] args) {
Set s = new HashSet();
List l = new ArrayList();
s.add("1");s.add("2");s.add("3");
l.add("a");l.add("b");l.add("c");
Collection c1 = convertSetList(s);
Collection c2 = convertSetList(l);
System.out.println("c1 type is : "+ c1.getClass());
System.out.println("c2 type is : "+ c2.getClass());
}
public static Collection convertSetList(Collection obj) {
if (obj instanceof java.util.List) {
System.out.println("List!");
return (Set)new HashSet((List) obj);
} else if (obj instanceof java.util.Set) {
System.out.println("Set!");
return (List)new ArrayList((Set) obj);
} else {
System.out.println("Unknow type!");
return null;
}
}
}
Related
I often have to deal with DTOs that contains other DTOs and I'd like to scan one object's attributes (and their own attributes, recursively) and retrieve every accessible object of class Bingo in the whole hierarchy.
For example, when I have the following :
public static class Bingo {
// the one I want to get
}
public static class Foo {
private Bar bar;
private Bingo bingo;
private List<Bingo> bingos;
// getters & setters
}
public static class Bar {
private Bingo bingo;
// getters & setters
}
I'd like to get all instances of Bingo found in attributes of my Foo object, including the ones in the Bar object and the List.
Is there a library conveniently doing that ?
A more complete test case (using a bit of JUnit) :
public static class Bingo {
private final int id;
public Bingo(int in_id) {
id = in_id;
}
#Override
public String toString() {
return "Bingo#"+String.valueOf(id);
}
}
public static class BingoWrapper {
private Bingo bingo;
public Bingo getBingo() {
return bingo;
}
public void setBingo(Bingo in_bingo) {
bingo = in_bingo;
}
}
public static class BingoFactory {
private final List<Bingo> ALL_BINGOS = new ArrayList<>();
private int sequence = 0;
public Bingo createBingo(){
Bingo l_bingo = new Bingo(sequence++);
ALL_BINGOS.add(l_bingo);
return l_bingo;
}
public BingoWrapper createBingoWrapper(){
BingoWrapper l_bar = new BingoWrapper();
l_bar.setBingo(createBingo());
return l_bar;
}
public List<Bingo> getAllBingos(){
return ALL_BINGOS.stream().collect(Collectors.toList());
}
}
public static class Foo {
private Bingo bingo;
private BingoWrapper wrapper;
private Bingo[] array;
private Collection<Object> collection;
private Map<Object,Object> map;
public Bingo getBingo() {
return bingo;
}
public void setBingo(Bingo in_bingo) {
bingo = in_bingo;
}
public BingoWrapper getWrapper() {
return wrapper;
}
public void setWrapper(BingoWrapper in_bar) {
wrapper = in_bar;
}
public Bingo[] getArray() {
return array;
}
public void setArray(Bingo[] in_array) {
array = in_array;
}
public Collection<Object> getCollection() {
return collection;
}
public void setCollection(Collection<Object> in_collection) {
collection = in_collection;
}
public Map<Object, Object> getMap() {
return map;
}
public void setMap(Map<Object, Object> in_map) {
map = in_map;
}
}
#Test
public void test(){
BingoFactory l_bingoFactory = new BingoFactory();
Foo l_foo = new Foo();
l_foo.setBingo(l_bingoFactory.createBingo()); // one in a field
l_foo.setWrapper(l_bingoFactory.createBingoWrapper()); // one in a field of a field
l_foo.setArray(new Bingo[]{l_bingoFactory.createBingo()}); // one in an array in a field
l_foo.setCollection(Arrays.asList(
l_bingoFactory.createBingo(), // one in Collection in a field
l_bingoFactory.createBingoWrapper())); // one in a field of an item in a Collection in a field
Map<Object,Object> l_map = new HashMap<>();
l_foo.setMap(l_map);
l_map.put("key", l_bingoFactory.createBingo()); // one as a key in a Map in a field
l_map.put(l_bingoFactory.createBingo(), "value"); // one as a value in a Map in a field
l_map.put("keyAgain", l_bingoFactory.createBingoWrapper()); // one wrapped in a value in a Map in a Field
l_map.put(l_bingoFactory.createBingoWrapper(), "valueAgain"); // one wrapped in a key in a Map in a field
List<Bingo> l_found = BeanUtils.scanObjectForType(l_foo, Bingo.class); // Magic happens here
System.out.println(l_found); // for debug
Assert.assertTrue(l_found.containsAll(l_bingoFactory.getAllBingos())); // I want them ALL
}
A solution with Spring's BeanUtils : (I've added a boolean to decide whereas objects of input class needed to be scanned or not. (i.e. do you expect your Bingo objects to contain other objects of type Bingo ?))
public static <T> List<T> scanObjectForType(Object in_object, Class<T> in_type, boolean in_scanSameType){
return scanObjectForType(in_object, in_type, in_scanSameType, new HashSet<>());
}
private static <T> List<T> scanObjectForType(Object in_object, Class<T> in_type, boolean in_scanSameType, Set<Object> in_alreadyScanned){
if(in_type == null){
throw new IllegalArgumentException("in_type should not be null");
}
if(in_object instanceof Class){
throw new IllegalArgumentException("in_type should not be a Class");
}
if(in_object == null || in_alreadyScanned.contains(in_object)){
return Collections.emptyList();
}
in_alreadyScanned.add(in_object); // to prevent infinite loop when inner object references outer object
if(in_type.isInstance(in_object)){
return Collections.singletonList((T) in_object);
}
List<T> l_result = new ArrayList<>();
if(in_type.isInstance(in_object)){
l_result.add((T) in_object);
if(!in_scanSameType){
return l_result;
}
}
if(in_object instanceof Object[]){
for(Object l_item : (Object[]) in_object){
l_result.addAll(scanObjectForType(l_item, in_type, in_scanSameType, in_alreadyScanned));
}
} else if(in_object instanceof Collection){
for(Object l_item : (Collection<Object>) in_object){
l_result.addAll(scanObjectForType(l_item, in_type, in_scanSameType, in_alreadyScanned));
}
} else if(in_object instanceof Map){
Map<Object,Object> l_map = (Map<Object,Object>) in_object;
for(Map.Entry<Object, Object> l_entry : l_map.entrySet()){
l_result.addAll(scanObjectForType(l_entry.getKey(), in_type, in_scanSameType, in_alreadyScanned));
l_result.addAll(scanObjectForType(l_entry.getValue(), in_type, in_scanSameType, in_alreadyScanned));
}
} else {
PropertyDescriptor[] l_descriptors = org.springframework.beans.BeanUtils.getPropertyDescriptors(in_object.getClass());
for(PropertyDescriptor l_descriptor : l_descriptors){
Method l_readMethod = l_descriptor.getReadMethod();
if(l_readMethod != null){
try {
Object l_readObject = l_readMethod.invoke(in_object);
if(l_readObject != null
&& !l_readObject.equals(in_object) // prevents infinite loops
&& !(l_readObject instanceof Class)){ // prevents weird loops when accessing properties of classes
l_result.addAll(scanObjectForType(l_readObject,in_type, in_scanSameType, in_alreadyScanned));
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// too bad but continue
LOGGER.warn("Got an error trying to access field : ", e);
continue;
}
}
}
}
return l_result;
}
Its limitations :
Only scan properties with public accessors
Does not scan Class types (to prevent scanning of the whole ClassLoader's classes, and because the use-case is DTO-oriented).
Relies on recursivity. I guess it might be prettier to implement a BeanVisitor object that operates on a loop over a Set of nested beans.
Will scan Objects returned by getter methods that may not be properties.
It's not tested with inheritence.
I wrote a Predicate code that takes any Object and tests it for the following conditions:
if Object type is String and contains "k" then it should return true.
if Object type is Integer and greater than 100 then it should return true.
if Object type is Employee which is class and having salary of employee greater than 60000, it should return true.
After writing that Predicate method I wrote the remove method that removes values from list according to Predicate method.
public class ConditionalRemove {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>(Arrays.asList("ramesh", "kushal", "suresh", "kc"));
System.out.println(conditionalRemove(list));
}
public static <T> List<T> conditionalRemove(ArrayList<T> list) {
ConditionCheck<T> cond = new ConditionCheck<>();
for (T t : list) {
if (cond.test(t)) {
list.remove(t);
}
}
return list;
}
static class ConditionCheck<T> implements Predicate<T> {
#Override
public boolean test(T t) {
if (t instanceof String) {
return (((String) t).contains("k"));
} else if (t instanceof Integer) {
return ((int) t > 100);
} else if (t instanceof Employee) {
return ((int) ((Employee) t).getSalary() < 60000);
}
return true;
}
}
}
After compiling this code I found Exception in thread "main" java.util.ConcurrentModificationException
The issue is you are updating the list when you are iterating over that. The issue can be fixed by updating code as
public static <T> List<T> conditionalRemove(ArrayList<T> list) {
ConditionCheck<T> cond = new ConditionCheck<>();
Iterator it = list.iterator();
while(it.hasNext())
{
it.next();
if (cond.test(t)) {
it.remove();
}
}
return list;
}
Since you're using Java 8, a functional approach would be to create a new filtered list:
public static <T> List<T> conditionalRemove(ArrayList<T> list) {
return list.stream()
.filter(new ConditionCheck<>())
.collect(Collectors.toList());
}
You can even replace the static inner class by just a method:
public static <T> List<T> conditionalRemove(ArrayList<T> list) {
return list.stream()
.filter(ConditionalRemove::test)
.collect(Collectors.toList());
}
private static <T> boolean test(T t) {
// your predicate implementation...
}
Don't reinvent the wheel: Use Collection#removeIf():
public static <T> List<T> conditionalRemove(ArrayList<T> list) {
list.removeIf(new ConditionCheck<>());
return list;
}
At one line, this is hardly worth the effort of creating a method to call... just make the single line call in-line:
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("ramesh", "kushal", "suresh", "kc"));
list.removeIf(new ConditionCheck<>());
System.out.println(list);
}
Some data structures throws the java.util.ConcurrentModificationException when you modify them during an iteration, in order to do that with success you need use a synchronized structure such as "CopyOnWriteArrayList", this is the java doc reference
Hope this can help you!
Regards.
I have an ArrayList filled with objects with attributes name and time. I would like to remove duplicates based on the name and keep only records with the latest time. So I have overriden equals and hashcode for name in my object and used code like this.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
changedRecentlyList.clear(); //static list
for(ChangedRecentlyTO to : toList) {
if(!changedRecentlyList.contains(to)) {
changedRecentlyList.add(to);
} else {
if(changedRecentlyList.get(changedRecentlyList.lastIndexOf(to)).getTimeChanged().before(to.getTimeChanged())) {
changedRecentlyList.remove(to);
changedRecentlyList.add(to);
}
}
}
return changedRecentlyList;
}
But I am wondering, is there a better solution?I was thinking about using Set but I am not able to figure out how should I put there the time criterion.
You have to me two ways, one which requires understanding how the set work, and one which is more understandable for people who have littler understanding of Java Collections:
If you want to make it simple, you can simply read in the detail the Javadoc of Set, http://docs.oracle.com/javase/6/docs/api/java/util/Set.html#add(E). It clearly states that if an element is already inside, it won't be added again.
You implement your equals and hashcode using only the name
You sort the items by time and then you add them to the Set.
In such a way, the first time you will add the item to Set, you will be adding the elements with the latest times. When you'll add the others, they will be ignored because they are already contained.
If someone else who does not know exactly the contract of java.util.Set behaves, you might want to extend Set to make your intention clearer. However, since a Set is not supposed to be accessed to "get back an element after removal", you will need to back your set with an HashMap:
interface TimeChangeable {
long getTimeChanged();
}
public class TimeChangeableSet<E extends TimeCheangeable> implements Set<E> {
private final HashMap<Integer,E> hashMap = new HashMap<Integer,E>();
#Override
public boolean add(E e) {
E existingValue = hashMap.remove(e.hashCode());
if(existingValue==null){
hashMap.put(e.hashCode(),e);
return true;
}
else{
E toAdd = e.getTimeChanged() > existingValue.getTimeChanged() ? e : existingValue;
boolean newAdded = e.getTimeChanged() > existingValue.getTimeChanged() ? true : false;
hashMap.put(e.hashCode(),e);
return newAdded;
}
}
#Override
public int size() {
return hashMap.size();
}
#Override
public boolean isEmpty() {
return hashMap.isEmpty();
}
#Override
public boolean contains(Object o) {
return hashMap.containsKey(o.hashCode());
}
#Override
public Iterator<E> iterator() {
return hashMap.values().iterator();
}
#Override
public Object[] toArray() {
return hashMap.values().toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return hashMap.values().toArray(a);
}
#Override
public boolean remove(Object o) {
return removeAndGet(o)!=null ? true : false;
}
public E removeAndGet (Object o) {
return hashMap.remove(o.hashCode());
}
#Override
public boolean containsAll(Collection<?> c) {
boolean containsAll = true;
for(Object object:c){
E objectInMap = removeAndGet(object);
if(objectInMap==null || !objectInMap.equals(object))
containsAll=false;
}
return containsAll;
}
#Override
public boolean addAll(Collection<? extends E> c) {
boolean addAll=true;
for(E e:c){
if(!add(e)) addAll=false;
}
return addAll;
}
#Override
public boolean retainAll(Collection<?> c) {
boolean setChanged=false;
for(E e: hashMap.values()){
if(!c.contains(e)){
hashMap.remove(e.hashCode());
setChanged=true;
}
}
return setChanged;
}
#Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("Please do not use type-unsafe methods in 2012");
}
#Override
public void clear() {
hashMap.clear();
}
}
Extend HashMap and override put method to put only if new object is more recent than the existing one.
Or, you can create your own dedicated container which will be backed by a HashMap, just like some implementations of Stack are backed by LinkedList
This is a mock code:
import java.util.HashMap;
import java.util.Map;
public class TimeMap<K, V> {
private Map<K, V> timeMap;
public TimeMap() {
this.timeMap = new HashMap<K, V>();
}
public void put(K key, V value) {
if (isNewer(key, value)) {
this.timeMap.put(key, value);
}
}
}
Why you dont use a Set and later:
new ArrayList(set);
A very quick implementation of what I had in mind.
Assumed the ChangedRecentlyTO object had a name property.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
Map<String, ChangedRecentlyTO> uniqueMap = new HashMap<String, ChangedRecentlyTO>();
for(ChangedRecentlyTO to : toList) {
if (uniqueMap.containsKey(to.getName())) {
if (uniqueMap.get(to.getName()).getTimeChanged().before(to.getTimeChanged())) {
uniqueMap.put(to.getName(), to);
}
} else {
uniqueMap.put(to.getName(), to);
}
}
return (List<ChangedRecentlyTO>) uniqueMap.values();
}
After all of that, it doesn't seem to different to your original implementation with the exception that there is no need override hashcode and equals.
You could let your class implement the Comparable interface and make compare check the timestamps you are interested in. If you then sort it (e.g. put all the elements in a TreeSet) and then get them out one by one, only if they don't already exist. Something like this:
public void removeDuplicates(List<MyObject> list){
SortedSet<MyObject> sortedSet = new TreeSet<MyObject>();
sortedSet.addAll(list);
//Now clear the list, and start adding them again
list.clear();
for(MyObject obj : sortedSet){
if(!list.contains(obj) {
list.add(obj);
}
}
return list;
}
This, however, will only work if two objects with different timestamps are not equal! (in the equals() sense of the word
What I would suggest , Make your class Comparable by implementing Comparable interface.Then in comparetTo() based on name and time compare them if object time is recent return 1 else 0(if equal) or -1 .Once you got this functionality you can extend HashMap class and override the put method like.
o1.compareTo(o2) > 0 then simply overwrite the object with latest one.
Adding logic to #Lopina code like
public class MyHashMap extends HashMap<String, MyClass>{
private Map<String, MyClass> timeMap;
public MyHashMap() {
this.timeMap = new HashMap<String, MyClass>();
}
public MyClass put(String key, MyClass value) {
MyClass obj;
if (isNewer(key, value)) {
System.out.println("count");
obj=this.timeMap.put(key, value);
}else{
obj=value;
}
return obj;
}
private boolean isNewer(String key, MyClass value) {
if(this.timeMap.get(key)==null ||( key.equals(value.getName()))&& (this.timeMap.get(key).compareTo(value))<0)
return true;
else
return false;
}
#Override
public int size() {
return this.timeMap.size();
}
#Override
public MyClass get(Object key) {
return this.timeMap.get(key);
}
}
In MyClass implement comparable interface and override compareTo method like below.
#Override
public int compareTo(MyClass o) {
return this.getTime().compareTo(o.getTime());
}
I wrote a UniqueList class that extends an ArrayList to back its data and utilises a HashSet to efficiently reject duplicates. This gives O(1) Random Access Time and many other speed improvements to manually sweeping the dataset.
https://gist.github.com/hopesenddreams/80730eaafdfe816ddbb1
public class UniqueList<T> extends ArrayList<T> implements Set<T>
{
HashMap<T,Integer> hash; // T -> int
public UniqueList()
{
hash = new HashMap<>();
}
/*
* O(n)
* */
#Override
public void add(int location, T object)
{
super.add(location, object);
for( int i = location ; i < size() ; i++ )
{
hash.put(get(i),i);
}
}
/*
* O(1) amortized.
* */
#Override
public boolean add(T object) {
if( hash.containsKey(object) ) return false;
hash.put(object, size());
super.add(object);
return true;
}
/*
* O(MAX(collection.size(),n)) because of the hash-value-shift afterwards.
* */
#Override
public boolean addAll(int location, Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put(t, size());
super.add(t);
bChanged = true;
}
}
for( int i = location + collection.size() ; i < size() ; i ++ )
{
hash.put( get(i) , i );
}
return bChanged;
}
/*
* O(collection.size())
* */
#Override
public boolean addAll(Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put( t , size() );
super.add(t);
bChanged = true;
}
}
return bChanged;
}
/*
* O(n)
* */
#Override
public void clear() {
hash.clear();
super.clear();
}
/*
* O(1)
* */
#Override
public boolean contains(Object object) {
return hash.containsKey(object);
}
/*
* O(collection.size())
* */
#Override
public boolean containsAll(Collection<?> collection) {
boolean bContainsAll = true;
for( Object c : collection ) bContainsAll &= hash.containsKey(c);
return bContainsAll;
}
/*
* O(1)
* */
#Override
public int indexOf(Object object) {
//noinspection SuspiciousMethodCalls
Integer index = hash.get(object);
return index!=null?index:-1;
}
/*
* O(1)
* */
#Override
public int lastIndexOf(Object object)
{
return hash.get(object);
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public T remove(int location) {
T t = super.remove(location);
hash.remove( t );
for( int i = size() - 1 ; i >= location ; i -- )
{
hash.put( get(i) , i );
}
return t;
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public boolean remove(Object object) {
Integer i = hash.get( object );
if( i == null ) return false;
remove( i.intValue() );
return true;
}
/*
* O( MAX( collection.size() , ArrayList.removeAll(collection) ) )
* */
#Override
public boolean removeAll(#NonNull Collection<?> collection) {
for( Object c : collection )
{
hash.remove( c );
}
return super.removeAll( collection );
}
}
I've done some fancy wrapping to avoid unchecked warnings in the past, but after 90 mins of poring over http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html, I can't write the findMatch method below and make it work without #SuppressWarnings("unchecked"). The parameterized class isn't known at compile time.
public interface Matchable<T>
{
public boolean matches(T toMatch);
}
public class PlaceForMatching
{
public static Object findMatch(Object toMatch, Object[] toSearch)
{
if(!(toMatch instanceof Matchable)) return null;
Matchable matchObj = (Matchable)toMatch;
Class<?> matchClass = matchObj.getClass();
for(Object obj : toSearch)
{
/**
* Check here verifies that the search list object we're about
* to check is the same class as the toMatch object.
* This means Matchable will work without a ClassCastException.
**/
if(matchClass.isInstance(obj) && matchObj.matches(obj))
return obj;
}
//Didn't find it
return null;
}
}
Note the code works because in every case Matchable is implemented by T.
Apple implements Matchable<Apple>
Orange implements Matchable<Orange>
EDIT: Add some test code
public static void main(String[] args)
{
Object[] randomList = createAppleArray();
Object apple = new Apple("Red");
Object match = findMatch(apple, randomList);
}
private static Object[] createAppleArray()
{
return new Object[] { new Apple("Pink"), new Apple("Red"), new Apple("Green") };
}
public class Apple implements Matchable<Apple>
{
String color;
public Apple(String color)
{
this.color = color;
}
public boolean matches(Apple apple)
{
return color.equals(apple.color);
}
}
public static <T extends Matchable<T>> T findMatch(T toMatch, T[] toSearch) {
if (toMatch == null)
return null;
Matchable<T> matchObj = toMatch;
Class<?> matchClass = matchObj.getClass();
for (T obj : toSearch) {
if (matchClass.isInstance(obj) && matchObj.matches(obj))
return obj;
}
return null;
}
The question but in C#. So does Java have C#'s command? I need it for Matches-SearchTerm-Files-relationship.
foreach(var i in BunchOfItems.SelectMany(k => k.Items)) {}
[Why not for-loops?]
I have done such structures in nested for loops but they soon become bloated. So I prefer something more succint like the above.
public static Stack<Integer[]> getPrintPoss(String s,File f,Integer maxViewPerF)
{
Stack<File> possPrint = new Stack<File>();
Integer[] poss = new Integer[4]();
int u,size;
for(File f:files)
{
size = f2S(f).length();
u = Math.min(maxViewsPerF,size);
for(int i=0; i<u;i++)
{
// Do something --- bloated, and soon out of control
// wants more succintly
}
}
return possPrint;
}
for (List<Object> lo : list) {
for (Object o : lo) {
// etc etc
}
}
I don't think there's a simpler solution.
If you can get the data into an Iterable<Iterable<T>>, then you can get from that to a flattened Iterable<T> using Guava's Iterables.concat method. If what you have is really an Iterable<S>, with some way to get from an S to an Iterable<T>, well, then you have to first use Iterables.transform to view that as the Iterable<Iterable<T>> needed by concat.
All this will look a lot nicer if and when Java has something resembling closures, but at least today it's possible.
http://guava-libraries.googlecode.com
With Java 8, you can say
Collection bunchOfItems = ...;
bunchOfItems.stream().flatMap(k::getItems).forEach(i -> /* operate on i */);
or
Item[] bunchOfItems = ...;
Stream.of(bunchOfItems).flatMap(k::getItems).forEach(i -> /* operate on i */);
depending upon whether you have a Collection or an Array.
Have about half a year patience until JDK7 is final which will include Closures. This provides simliar syntax and the same possibilities as LINQ which was demonstrated in the answer you're talking about.
I have my own version. Waiting desperately for Closures in Java :
public static <T, E> Iterable<T> transformMany(Iterable<E> iterable, Func<E, Iterable<T>> f) {
if (null == iterable)
throw new IllegalArgumentException("null iterable");
if (null == f)
throw new IllegalArgumentException("null f");
return new TransformManyIterable<E, T>(iterable, f);
}
public interface Func<E, T> {
T execute(E e);
}
public class TransformManyIterable<TOriginal, TResult> implements Iterable<TResult> {
private Iterable<TOriginal> iterable;
private Func<TOriginal, Iterable<TResult>> func;
public TransformManyIterable(Iterable<TOriginal> iterable,
Func<TOriginal, Iterable<TResult>> func) {
super();
this.iterable = iterable;
this.func = func;
}
class TransformIterator implements Iterator<TResult> {
private Iterator<TOriginal> iterator;
private Iterator<TResult> currentIterator;
public TransformIterator() {
iterator = iterable.iterator();
}
#Override
public boolean hasNext() {
if (currentIterator != null && currentIterator.hasNext())
return true;
else {
while (iterator.hasNext()) {
Iterable<TResult> iterable = func.execute(iterator.next());
if (iterable == null)
continue;
currentIterator = iterable.iterator();
if (currentIterator.hasNext())
return true;
}
}
return false;
}
#Override
public TResult next() {
if (currentIterator != null && currentIterator.hasNext())
return currentIterator.next();
else {
while (iterator.hasNext()) {
Iterable<TResult> iterable = func.execute(iterator.next());
if (iterable == null)
continue;
currentIterator = iterable.iterator();
if (currentIterator.hasNext())
return currentIterator.next();
}
}
throw new NoSuchElementException();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
#Override
public Iterator<TResult> iterator() {
return new TransformIterator();
}
}
Usage:
Iterable<SomeType> result = transformMany(input, new Func<InputType, Iterable<SomeType>>() {
#Override
public Iterable<SomeType> execute(InputType e) {
return new ArrayList<SomeType>();
}
});
The SelectMany method is part of LINQ which is .Net-specific. This question asks about a LINQ equilvalent for java. Unfortunately, it doesn't look like there is a direct equivalent.