컬렉션 병합
내가 가지고 있다고 Map<? extends Object, List<String>>
맵의 값을 쉽게 얻을 수 있으며이를 반복하여 단일 List<String>
.
for (List<String> list : someMap.values()) {
someList.addAll(list);
}
한 번에 평면화하는 방법이 있습니까?
List<String> someList = SomeMap.values().flatten();
Java 8을 사용하는 경우 다음과 같이 할 수 있습니다.
someMap.values().forEach(someList::addAll);
Java 8을 사용 List
하고 제안 된 (및 허용 된) 솔루션 에서처럼 인스턴스를 직접 인스턴스화하지 않으려는 경우
someMap.values().forEach(someList::addAll);
다음 문으로 스트리밍하여 모든 작업을 수행 할 수 있습니다.
List<String> someList = map.values().stream().flatMap(c -> c.stream()).collect(Collectors.toList());
그건 그렇고, Java 8에서 허용되는 버전이 실제로 가장 빠르다는 것을 아는 것은 흥미로울 것입니다. 그것은 거의 같은 타이밍을 가지고
for (List<String> item : someMap.values()) ...
순수한 스트리밍 솔루션보다 빠른 방법입니다. 여기 내 작은 테스트 코드가 있습니다. 벤치 마크 결함에 대한 논의를 피하기 위해 벤치 마크 이름을 명시 적으로 지정하지 않습니다. ;) 완전한 컴파일 버전을 얻기 위해 모든 테스트를 두 번 수행합니다.
Map<String, List<String>> map = new HashMap<>();
long millis;
map.put("test", Arrays.asList("1", "2", "3", "4"));
map.put("test2", Arrays.asList("10", "20", "30", "40"));
map.put("test3", Arrays.asList("100", "200", "300", "400"));
int maxcounter = 1000000;
System.out.println("1 stream flatmap");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> someList = map.values().stream().flatMap(c -> c.stream()).collect(Collectors.toList());
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("1 parallel stream flatmap");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> someList = map.values().parallelStream().flatMap(c -> c.stream()).collect(Collectors.toList());
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("1 foreach");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> mylist = new ArrayList<String>();
map.values().forEach(mylist::addAll);
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("1 for");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> mylist = new ArrayList<String>();
for (List<String> item : map.values()) {
mylist.addAll(item);
}
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("2 stream flatmap");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> someList = map.values().stream().flatMap(c -> c.stream()).collect(Collectors.toList());
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("2 parallel stream flatmap");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> someList = map.values().parallelStream().flatMap(c -> c.stream()).collect(Collectors.toList());
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("2 foreach");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> mylist = new ArrayList<String>();
map.values().forEach(mylist::addAll);
}
System.out.println(System.currentTimeMillis() - millis);
System.out.println("2 for");
millis = System.currentTimeMillis();
for (int i = 0; i < maxcounter; i++) {
List<String> mylist = new ArrayList<String>();
for (List<String> item : map.values()) {
mylist.addAll(item);
}
}
System.out.println(System.currentTimeMillis() - millis);
결과는 다음과 같습니다.
1 stream flatmap
468
1 parallel stream flatmap
1529
1 foreach
140
1 for
172
2 stream flatmap
296
2 parallel stream flatmap
1482
2 foreach
156
2 for
141
2016-05-24 수정 (2 년 후) :
동일한 시스템에서 실제 Java 8 버전 (U92)을 사용하여 동일한 테스트 실행 :
1 stream flatmap
313
1 parallel stream flatmap
3257
1 foreach
109
1 for
141
2 stream flatmap
219
2 parallel stream flatmap
3830
2 foreach
125
2 for
140
스트림의 순차 처리 속도가 빨라지고 병렬 스트림의 경우 더 큰 오버 헤드가있는 것 같습니다.
2018-10-18 수정 (2 년 후) :
동일한 시스템에서 현재 Java 10 버전 (10.0.2) 사용 :
1 stream flatmap
393
1 parallel stream flatmap
3683
1 foreach
157
1 for
175
2 stream flatmap
243
2 parallel stream flatmap
5945
2 foreach
128
2 for
187
병렬 스트리밍의 오버 헤드가 더 큰 것 같습니다.
"java 8 flatten"을 검색 할 때 이것이 유일한 언급입니다. 그리고 그것은 평탄화에 관한 것도 아닙니다. 그래서 대단한 일을 위해 여기에 남겨 둡니다.
.flatMap(Collection::stream)
나는 또한 아무도 원래 질문에 대한 동시 자바 8 답변을주지 않았다는 것에 놀랐습니다.
.collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
동료의 제안 :
listOfLists.stream().flatMap(e -> e.stream()).collect(Lists.toList())
forEach ()보다 좋습니다.
당신이 사용하는 경우 이클립스 컬렉션 , 당신이 사용할 수있는 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.
No, there is no shorter method. You have to use a loop.
Update Apr 2014: Java 8 has finally come out. In the new version you can use the Iterable.forEach
method to walk over a collection without using an explicit loop.
Update Nov 2017: Found this question by chance when looking for a modern solution. Ended up going with reduce
:
someMap.values().stream().reduce(new ArrayList(), (accum, list) -> {
accum.addAll(list);
return accum;
}):
This avoids depending on mutable external state of forEach(someList::addAll)
the overhead of flatMap(List::stream)
.
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>>
참고URL : https://stackoverflow.com/questions/18290935/flattening-a-collection
'IT TIP' 카테고리의 다른 글
Java에서 버전 문자열을 비교하는 효율적인 방법 (0) | 2020.12.13 |
---|---|
Mongoose를 사용하여 ObjectId로 검색하는 문서를 찾을 수 없습니다. (0) | 2020.12.13 |
우분투에서 Eclipse IDE를 사용하여 Tomcat 6 서버 생성 (0) | 2020.12.13 |
Linux 쉘에서 16 진수를 ASCII 문자로 변환하는 방법은 무엇입니까? (0) | 2020.12.13 |
Ubuntu에서 X11 / Xlib.h를 찾을 수 없음 (0) | 2020.12.13 |