Moh*_*air 4 java-8 java-stream
我想使用java8流合并内部列表,如下所示:
什么时候
List<List<Integer>> mainList = new ArrayList<List<Integer>>();
mainList.add(Arrays.asList(0,1));
mainList.add(Arrays.asList(0,1,2));
mainList.add(Arrays.asList(1,2));
mainList.add(Arrays.asList(3));
Run Code Online (Sandbox Code Playgroud)
应该合并成
[[0,1,2],[3]];
Run Code Online (Sandbox Code Playgroud)
什么时候
List<List<Integer>> mainList = new ArrayList<List<Integer>>();
mainList.add(Arrays.asList(0,2));
mainList.add(Arrays.asList(1,4));
mainList.add(Arrays.asList(0,2,4));
mainList.add(Arrays.asList(3,4));
mainList.add(Arrays.asList(1,3,4));
Run Code Online (Sandbox Code Playgroud)
应该合并成
[[0,1,2,3,4]];
Run Code Online (Sandbox Code Playgroud)
到目前为止,这是我所做的
static void mergeCollections(List<List<Integer>> collectionTomerge) {
boolean isMerge = false;
List<List<Integer>> mergeCollection = new ArrayList<List<Integer>>();
for (List<Integer> listInner : collectionTomerge) {
List<Integer> mergeAny = mergeCollection.stream().map(
lc -> lc.stream().filter(listInner::contains)
).findFirst()
.orElse(null)
.collect(Collectors.toList());
}
}
Run Code Online (Sandbox Code Playgroud)
但我得到这个例外:
Exception in thread "main" java.lang.NullPointerException
at linqArraysOperations.LinqOperations.mergeCollections(LinqOperations.java:87)
Run Code Online (Sandbox Code Playgroud)
更新了我的答案版本
这就是我想要实现的目标,但Tagir的好回答是没有递归
我通过使用Tagir回答没有平面地图的逻辑,在Mikhaal的回答中做了一些改变
public static <T> List<List<T>> combineList(List<List<T>> argList) {
boolean isMerge = false;
List<List<T>> result = new ArrayList<>();
for (List<T> list : argList) {
List<List<T>> mergedFound =
result.stream()
.filter(mt->list.stream().anyMatch(mt::contains))
.map(
t -> Stream.concat(t.stream(),list.stream()).distinct()
.collect(Collectors.toList())
)
.collect(Collectors.toList());
//if(mergedFound !=null && ( mergedFound.size() > 0 && mergedFound.stream().findFirst().get().size() > 0 )){
if(mergedFound !=null && mergedFound.size() > 0 && ){
result = Stream.concat(result.stream().filter(t->list.stream().noneMatch(t::contains)),mergedFound.stream()).distinct().collect(Collectors.toList());
isMerge = true;
}
else
result.add(list);
}
if(isMerge && result.size() > 1)
return combineList(result);
return result;
}
Run Code Online (Sandbox Code Playgroud)
这是非常简单但不是非常有效的解决方案:
static List<List<Integer>> mergeCollections(List<List<Integer>> input) {
List<List<Integer>> result = Collections.emptyList();
for (List<Integer> listInner : input) {
List<Integer> merged = Stream.concat(
// read current results and select only those which contain
// numbers from current list
result.stream()
.filter(list -> list.stream().anyMatch(listInner::contains))
// flatten them into single stream
.flatMap(List::stream),
// concatenate current list, remove repeating numbers and collect
listInner.stream()).distinct().collect(Collectors.toList());
// Now we need to remove used lists from the result and add the newly created
// merged list
result = Stream.concat(
result.stream()
// filter out used lists
.filter(list -> list.stream().noneMatch(merged::contains)),
Stream.of(merged)).collect(Collectors.toList());
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
棘手的部分是,接下来listInner可能会合并已经添加的几个列表.例如,如果我们有部分结果[[1, 2], [4, 5], [7, 8]],并处理新的listInner内容[2, 3, 5, 7],那么部分结果应该变为[[1, 2, 3, 4, 5, 7, 8]](即所有列表合并在一起).因此,在每次迭代中,我们都在寻找现有的部分结果,这些结果具有与当前数字相同的数字listInner,将它们展平,与当前数据连接listInner并转储到新merged列表中.接下来,我们从当前使用的结果列表中过滤掉merged并添加merged.
您可以使用partitioningBy收集器立即执行两个过滤步骤,使解决方案更有效:
static List<List<Integer>> mergeCollections(List<List<Integer>> input) {
List<List<Integer>> result = Collections.emptyList();
for (List<Integer> listInner : input) {
// partition current results by condition: whether they contain
// numbers from listInner
Map<Boolean, List<List<Integer>>> map = result.stream().collect(
Collectors.partitioningBy(
list -> list.stream().anyMatch(listInner::contains)));
// now map.get(true) contains lists which intersect with current
// and should be merged with current
// and map.get(false) contains other lists which should be preserved
// in result as is
List<Integer> merged = Stream.concat(
map.get(true).stream().flatMap(List::stream),
listInner.stream()).distinct().collect(Collectors.toList());
result = Stream.concat(map.get(false).stream(), Stream.of(merged))
.collect(Collectors.toList());
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
这里map.get(true)包含列表,其中包含元素,listInner并map.get(false)包含应从上一结果中保留的其他列表.
元素的顺序可能与您期望的不同,但您可以轻松地对嵌套列表进行排序,或者根据需要使用List<TreeSet<Integer>>结果数据结构.
| 归档时间: |
|
| 查看次数: |
970 次 |
| 最近记录: |