递归地展平包含未知级别的嵌套数组和映射的嵌套映射
Flatten nested Map containing with unknown level of nested Arrays and Maps recursively
我有一个带有 String
键的嵌套 HashMap
,其中包含 List
、Map
或 String
值。我想像下面那样把它们压平。
这是数据:
import java.util.*;
import java.util.stream.*;
public class MyClass {
public static void main(String args[]) {
Map<String, Object> dates = new HashMap<String, Object>() {{
put("1999", new HashMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", "3"));
}});
put("2001", new HashMap<String, Object>() {{
put("11", new HashMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
System.out.println(dates);
}
}
地图看起来像:
{2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45},
1999={3=[23, 24, 25], 4=[1, 2, 3]}}
地图的扁平化应该是这样的:
{2001.11.7.1=23, 2001.11.7.2=24, 2001.11.7.3=25, 2001.11.9.1=1, 2001.11.9.2=2,
2001.11.9.3=3, 2001.12=45, 1999.3.1=23, 1999.3.2=24, 1999.3.3=25,
1999.4.1=1, 1999.4.2=2, 1999.4.3=3}
注意:嵌套数组或映射的层级未知,可能超过 2 层。
您可以使用递归来展平Map
。每次遇到 Map
时,通过展平 Map
进行递归;当您遇到 List
时,对其进行迭代并将索引添加到当前键。否则可以简单地设置单个值。请参阅下面的代码 here.
public static Map<String, Object> flatten(final Map<String, Object> map) {
return flatten("", map, new HashMap<>());
//use new TreeMap<>() to order map based on key
}
@SuppressWarnings("unchecked")//recursive helper method
private static Map<String, Object> flatten(final String key, final Map<String, Object> map,
final Map<String, Object> result) {
final Set<Map.Entry<String, Object>> entries = map.entrySet();
if (!entries.isEmpty()) {
for (final Map.Entry<String, Object> entry : entries) {
//iterate over entries
final String currKey = key + (key.isEmpty() ? "" : '.') + entry.getKey();
//append current key to previous key, adding a dot if the previous key was not an empty String
final Object value = entry.getValue();
if (value instanceof Map) {//current value is a Map
flatten(currKey, (Map<String, Object>) value, result);//flatten Map
} else if (value instanceof List) {//current value is a List
final List<Object> list = (List<Object>) value;
for (int i = 0, size = list.size(); i < size; i++) {
result.put(currKey + '.' + (i + 1), list.get(i));
}
//iterate over the List and append the index to the current key when setting value
} else {
result.put(currKey, value);//set normal value
}
}
}
return result;
}
public static void main(final String[] args){
final Map<String, Object> flattened = flatten(dates);
System.out.println(flattened);
}
您可以遍历此映射,并根据其实例处理每个条目值:Map
、List
或 String
。由于 嵌套数组或映射的级别未知 ,为了清楚起见,我对您的代码示例和平面地图格式做了一些修改,我还使用 TreeMap
而不是 HashMap
用于条目排序。
public static void main(String[] args) {
TreeMap<String, Object> treeMap = new TreeMap<String, Object>() {{
put("1999", new TreeMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", new TreeMap<String, Object>() {{
put("10", "42");
}}));
}});
put("2001", new TreeMap<String, Object>() {{
put("11", new TreeMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
TreeMap<String, String> flatMap = new TreeMap<>();
processMap("", treeMap, flatMap);
System.out.println(treeMap);
System.out.println(flatMap);
}
private static void processMap(String prefix,
Map<String, Object> map,
Map<String, String> flatMap) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
processEntry(prefix, key, value, flatMap);
}
}
private static void processList(String prefix,
List<Object> list,
Map<String, String> flatMap) {
for (int i = 0; i < list.size(); i++) {
String key = String.valueOf(i + 1);
Object value = list.get(i);
processEntry(prefix, key, value, flatMap);
}
}
@SuppressWarnings("unchecked")
private static void processEntry(String prefix,
String key,
Object value,
Map<String, String> flatMap) {
if (value instanceof Map) {
processMap(prefix + key + ".", (Map<String, Object>) value, flatMap);
} else if (value instanceof List) {
processList(prefix + key + ":", (List<Object>) value, flatMap);
} else if (value instanceof String) {
flatMap.put(prefix + key, (String) value);
}
}
示例地图:
{1999={3=[23, 24, 25], 4=[1, 2, {10=42}]},
2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45}}
扁平化地图:
{1999.3:1=23, 1999.3:2=24, 1999.3:3=25, 1999.4:1=1, 1999.4:2=2, 1999.4:3.10=42,
2001.11.7:1=23, 2001.11.7:2=24, 2001.11.7:3=25,
2001.11.9:1=1, 2001.11.9:2=2, 2001.11.9:3=3, 2001.12=45}
相反:.
我有一个带有 String
键的嵌套 HashMap
,其中包含 List
、Map
或 String
值。我想像下面那样把它们压平。
这是数据:
import java.util.*;
import java.util.stream.*;
public class MyClass {
public static void main(String args[]) {
Map<String, Object> dates = new HashMap<String, Object>() {{
put("1999", new HashMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", "3"));
}});
put("2001", new HashMap<String, Object>() {{
put("11", new HashMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
System.out.println(dates);
}
}
地图看起来像:
{2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45},
1999={3=[23, 24, 25], 4=[1, 2, 3]}}
地图的扁平化应该是这样的:
{2001.11.7.1=23, 2001.11.7.2=24, 2001.11.7.3=25, 2001.11.9.1=1, 2001.11.9.2=2,
2001.11.9.3=3, 2001.12=45, 1999.3.1=23, 1999.3.2=24, 1999.3.3=25,
1999.4.1=1, 1999.4.2=2, 1999.4.3=3}
注意:嵌套数组或映射的层级未知,可能超过 2 层。
您可以使用递归来展平Map
。每次遇到 Map
时,通过展平 Map
进行递归;当您遇到 List
时,对其进行迭代并将索引添加到当前键。否则可以简单地设置单个值。请参阅下面的代码 here.
public static Map<String, Object> flatten(final Map<String, Object> map) {
return flatten("", map, new HashMap<>());
//use new TreeMap<>() to order map based on key
}
@SuppressWarnings("unchecked")//recursive helper method
private static Map<String, Object> flatten(final String key, final Map<String, Object> map,
final Map<String, Object> result) {
final Set<Map.Entry<String, Object>> entries = map.entrySet();
if (!entries.isEmpty()) {
for (final Map.Entry<String, Object> entry : entries) {
//iterate over entries
final String currKey = key + (key.isEmpty() ? "" : '.') + entry.getKey();
//append current key to previous key, adding a dot if the previous key was not an empty String
final Object value = entry.getValue();
if (value instanceof Map) {//current value is a Map
flatten(currKey, (Map<String, Object>) value, result);//flatten Map
} else if (value instanceof List) {//current value is a List
final List<Object> list = (List<Object>) value;
for (int i = 0, size = list.size(); i < size; i++) {
result.put(currKey + '.' + (i + 1), list.get(i));
}
//iterate over the List and append the index to the current key when setting value
} else {
result.put(currKey, value);//set normal value
}
}
}
return result;
}
public static void main(final String[] args){
final Map<String, Object> flattened = flatten(dates);
System.out.println(flattened);
}
您可以遍历此映射,并根据其实例处理每个条目值:Map
、List
或 String
。由于 嵌套数组或映射的级别未知 ,为了清楚起见,我对您的代码示例和平面地图格式做了一些修改,我还使用 TreeMap
而不是 HashMap
用于条目排序。
public static void main(String[] args) {
TreeMap<String, Object> treeMap = new TreeMap<String, Object>() {{
put("1999", new TreeMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", new TreeMap<String, Object>() {{
put("10", "42");
}}));
}});
put("2001", new TreeMap<String, Object>() {{
put("11", new TreeMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
TreeMap<String, String> flatMap = new TreeMap<>();
processMap("", treeMap, flatMap);
System.out.println(treeMap);
System.out.println(flatMap);
}
private static void processMap(String prefix,
Map<String, Object> map,
Map<String, String> flatMap) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
processEntry(prefix, key, value, flatMap);
}
}
private static void processList(String prefix,
List<Object> list,
Map<String, String> flatMap) {
for (int i = 0; i < list.size(); i++) {
String key = String.valueOf(i + 1);
Object value = list.get(i);
processEntry(prefix, key, value, flatMap);
}
}
@SuppressWarnings("unchecked")
private static void processEntry(String prefix,
String key,
Object value,
Map<String, String> flatMap) {
if (value instanceof Map) {
processMap(prefix + key + ".", (Map<String, Object>) value, flatMap);
} else if (value instanceof List) {
processList(prefix + key + ":", (List<Object>) value, flatMap);
} else if (value instanceof String) {
flatMap.put(prefix + key, (String) value);
}
}
示例地图:
{1999={3=[23, 24, 25], 4=[1, 2, {10=42}]},
2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45}}
扁平化地图:
{1999.3:1=23, 1999.3:2=24, 1999.3:3=25, 1999.4:1=1, 1999.4:2=2, 1999.4:3.10=42,
2001.11.7:1=23, 2001.11.7:2=24, 2001.11.7:3=25,
2001.11.9:1=1, 2001.11.9:2=2, 2001.11.9:3=3, 2001.12=45}
相反: