如何将嵌套集合中的所有项目展平为单个列表? [英] How to flatten all items from a nested Collection into a single List?
问题描述
给定复杂的嵌套对象集合,例如:
Given a complex nested collection of objects such as:
Set<List<Map<String, List<Object>>>> complexNestedCollection;
是否有一个通用的方法来展开这个方法并获取单个 / code>
Does a generic method exist to flatten this out and get a single List
of all Object
s contained within?
一些细节:
- 此列表不应包含集合对象本身或地图键 - 只包含最低级别的值。
- 应该在可能的情况下遵循相同的顺序 - 因此在示例中,列表中的项目将是有序的,而地图/集合的排序将取决于实现。
- UPDATE:应理想地检测/处理任何级别的循环引用,例如a
List< List< Object>>
,其中外部List包含自身作为成员。 (请注意,AdrianJałoszewski在下面的评论中提到了这一点)。
- The list shouldn't include collection objects themselves or map keys - only the values at the lowest level.
- It should follow the same ordering where possible - so in the example, items in the list would be in order, whereas ordering of maps/sets would depend on the implementation.
- It could optionally exclude duplicates
- UPDATE: It should ideally detect/handle circular references at any level, e.g. a
List<List<Object>>
where the outer List contains itself as a member. (Credit to Adrian Jałoszewski for mentioning this in the comments below).
注意:从 List< List< String>>
的字符串,这可以很容易做到两个循环,但它让我想知道一般情况。 p>
Note: The actual use case is to get all Strings from a List<List<String>>
, which can be done easily enough with two loops but it made me wonder about the general case.
推荐答案
这是一个FlattenEverythingButTheKitchenSink类,稍微修改一个上一个答案。它使用Java 7和Java 8测试。
Here is a FlattenEverythingButTheKitchenSink class, a slightly modified version of a previous answer. It was tested with Java 7 and Java 8.
它可以与列表,集合,地图,队列,甚至任意深度的数组。
它编译和运行没有警告,我找不到任何反例。因此类名:)
It works with Lists, Sets, Maps, Queues, and even Arrays of arbitrary depth. It compiles and runs without warning, and I couldn't find any counterexample. Hence the class name :)
如果你想要一个对象列表有可能的重复,使用flatten,如果你想要一个集合,使用uniqFlatten。
If you want a List of objects with possible duplicates, use flatten, if you want a Set, use uniqFlatten.
EDITED:重构以避免代码重复。
EDITED: Refactoring to avoid code repetition.
package stackOverflow;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
// Answer for
// http://stackoverflow.com/questions/20144826/how-to-flatten-all-items-from-a-nested-collection-into-a-single-list
public class FlattenEverythingButTheKitchenSink
{
public static void main(String[] args) {
int[][][] int3dArray = { { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } },
{ { 10, 11, 12 }, { 13, 14, 15 }, { 16, 17, 18 } },
{ { 19, 20, 21 }, { 22, 23, 24 }, { 25, 26, 27 }, { 28 }, { 29, 30 } } };
String[][] string2dArray = { { "He, llo" }, { "Wo", "rld" } };
String[] stringArray = { "Hello", "World" };
Set<Integer> integersSet = new HashSet<Integer>();
integersSet.add(1);
integersSet.add(2);
integersSet.add(3);
Map<String, String> stringMap = new HashMap<>();
stringMap.put("key1", "value1");
stringMap.put("key2", "value2");
stringMap.put("key3", "value3");
Queue<String> qe = new LinkedList<String>();
qe.add("x");
qe.add("y");
qe.add("z");
Object[] objectArray = { "Hell", 0, "W", 0, "orld", integersSet, stringMap, qe };
List<Object> mixList = new ArrayList<Object>();
mixList.add("String");
mixList.add(3);
mixList.add(string2dArray);
System.out.println(flatten(int3dArray));
System.out.println(flatten(flatten(int3dArray)));
System.out.println(flatten(3));
System.out.println(flatten(stringArray));
System.out.println(flatten(string2dArray));
System.out.println(flatten(objectArray));
System.out.println(flatten(mixList));
mixList.add(int3dArray);
System.out.println(uniqFlatten(mixList));
}
public static List<Object> flatten(Object object) {
return (List<Object>) recursiveFlatten(object, true);
}
public static Set<Object> uniqFlatten(Object object) {
return (Set<Object>) recursiveFlatten(object, false);
}
private static Collection<Object> recursiveFlatten(Object object, Boolean allowDuplicates) {
Collection<Object> setOrList;
if (allowDuplicates) {
setOrList = new ArrayList<Object>();
} else {
setOrList = new LinkedHashSet<Object>();
}
if (object.getClass().isArray()) {
for (int i = 0; i < Array.getLength(object); i++) {
setOrList.addAll(recursiveFlatten(Array.get(object, i), allowDuplicates));
}
} else if (object instanceof Map) {
for (Object element : ((Map<?, ?>) object).values()) {
setOrList.addAll(recursiveFlatten(element, allowDuplicates));
}
} else if (object instanceof Iterable) {
for (Object element : (Iterable<?>) object) {
setOrList.addAll(recursiveFlatten(element, allowDuplicates));
}
} else {
setOrList.add(object);
}
return setOrList;
}
}
它输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
[3]
[Hello, World]
[He, llo, Wo, rld]
[Hell, 0, W, 0, orld, 1, 2, 3, value1, value2, value3, x, y, z]
[String, 3, He, llo, Wo, rld]
[String, 3, He, llo, Wo, rld, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
且不应有任何问题
Set<List<Map<String, List<Object>>>> complexNestedCollection;
它也适用于
Set<List<Map<String, List<int[][][][]>>>>
初始化代码不会很漂亮:D
The initialisation code wouldn't be pretty though :D
这篇关于如何将嵌套集合中的所有项目展平为单个列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!