Say I have a Map extends Object, List
I can get the values of the map easily enough, and iterate over it to produce a single
When searching for "java 8 flatten" this is the only mentioning. And it's not about flattening stream either. So for great good I just leave it here
.flatMap(Collection::stream)
I'm also surprised no one has given concurrent java 8 answer to original question which is
.collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
Flatten on a function:
private <A, T> List<T> flatten(List<A> list, Function<A, List<T>> flattenFn) {
return list
.stream()
.map(flattenFn)
.flatMap(Collection::stream)
.collect(Collectors.toUnmodifiableList());
}
If you are using Java 8, you could do something like this:
someMap.values().forEach(someList::addAll);
If you just want to iterate through values, you can avoid all these addAll methods.
All you have to do is write a class that encapsulates your Map, and that implements the Iterator :
public class ListMap<K,V> implements Iterator<V>
{
private final Map<K,List<V>> _map;
private Iterator<Map.Entry<K,List<V>>> _it1 = null;
private Iterator<V> _it2 = null;
public ListMap(Map<K,List<V>> map)
{
_map = map;
_it1 = map.entrySet().iterator();
nextList();
}
public boolean hasNext()
{
return _it2!=null && _it2.hasNext();
}
public V next()
{
if(_it2!=null && _it2.hasNext())
{
return _it2.next();
}
else
{
throw new NoSuchElementException();
}
nextList();
}
public void remove()
{
throw new NotImplementedException();
}
private void nextList()
{
while(_it1.hasNext() && !_it2.hasNext())
{
_it2 = _it1.next().value();
}
}
}
A nice solution for the subcase of a Map of Maps is to store, if possible, the data in Guava's Table
.
https://github.com/google/guava/wiki/NewCollectionTypesExplained#table
So for instance a Map<String,Map<String,String>>
is replaced by Table<String,String,String>
which is already flattend. In fact, the docs say that HashBasedTable
, Table
's Hash implementation, is essentially backed by a HashMap<R, HashMap<C, V>>
If you're using Eclipse Collections, you can use Iterate.flatten().
MutableMap<String, MutableList<String>> map = Maps.mutable.empty();
map.put("Even", Lists.mutable.with("0", "2", "4"));
map.put("Odd", Lists.mutable.with("1", "3", "5"));
MutableList<String> flattened = Iterate.flatten(map, Lists.mutable.empty());
Assert.assertEquals(
Lists.immutable.with("0", "1", "2", "3", "4", "5"),
flattened.toSortedList());
flatten()
is a special case of the more general RichIterable.flatCollect().
MutableList<String> flattened =
map.flatCollect(x -> x, Lists.mutable.empty());
Note: I am a committer for Eclipse Collections.