比较两个 Maps<String, List<String>> 得到 map key + map value 作为差异
Compare two Maps<String, List<String>> and get map key + map value as differences
我有两个 Map 类型的映射,我需要比较它们,当我在列表中得到不同的值时,我需要用它们对应的映射检索这些值 key.The 两个映射看起来像这样:
Map<String, List<String>> map1 = new TreeMap<>();
Map<String, List<String>> map2 = new TreeMap<>();
map1.put("Column1", Arrays.asList("one", "two", "four"));
map1.put("Column2", Arrays.asList("one", "two", "four"));
map2.put("Column1", Arrays.asList("one", "two", "three"));
map2.put("Column2", Arrays.asList("one", "two", "three"));
比较后,结果应该是这样的:“键 1 的值不同,元素 3。键 2 的值不同,元素 3”。我如何遍历两个给定的映射,以便获得不同元素的相应索引?我尝试从每个 Map 创建一个 flatMap,但随后我丢失了列表之间不同元素的 keySet。
有很多方法可以进行比较(例如顺序很重要?如果不是,请使用 Set
而不是 List
)。
比较“不同元素对应索引”的一种方法是:
Map<String, List<String>> diffs = Streams.concat(xs.keySet().stream(), ys.keySet().stream())
.distinct()
.collect(toMap(k -> k, k -> {
List<String> x = xs.getOrDefault(k, emptyList());
List<String> y = ys.getOrDefault(k, emptyList());
return IntStream.range(0, Math.max(x.size(), y.size()))
.mapToObj(i -> i < x.size() ? (i < y.size() ? (x.get(i).equals(y.get(i)) ? "=": "<>"): "X") : "Y")
.collect(toList());
}));
如果索引 i
处的元素相等,则得到 =
,如果不同,则得到 <>
,如果该索引存在,则得到 X
或 Y
只有一套。
例如:
xs.put("Column1", Arrays.asList("one", "xxx", "four"));
xs.put("Column2", Arrays.asList("one", "two"));
xs.put("Column3", Arrays.asList("cat"));
ys.put("Column1", Arrays.asList("one", "two", "four"));
ys.put("Column2", Arrays.asList("one", "two", "three"));
ys.put("Column4", Arrays.asList("apple"));
有输出
{ Column1=[=, <>, =]
, Column2=[=, =, Y]
, Column3=[X]
, Column4=[Y]
}
这是一种方法。在不知道数据的性质的情况下,至少提及边界情况很重要。
- 首先,你的例子暗示你在做位置差异。所以
"one","two"
与 "two","one"
不同,因此被标记为 elements 0, 1
不同。
- 地图可能有不同的键。这意味着对于任何给定的键,缺少该键的映射内容都是不同的。
- 对应键的列表可能有不同数量的元素。前几个可能是一样的。任何元素缺失而不仅仅是不同的元素都会被标记出来。
这是数据
Map<String, List<String>> map1 = new TreeMap<>();
Map<String, List<String>> map2 = new TreeMap<>();
map1.put("Column1", Arrays.asList("one", "two", "four"));
map1.put("Column2", Arrays.asList("one", "two", "four"));
map1.put("Column3", Arrays.asList("three", "two"));
map1.put("Column4", Arrays.asList("one","two","three"));
map1.put("Column6", Arrays.asList("nine","ten"));
map2.put("Column1", Arrays.asList("one", "two", "three"));
map2.put("Column2", Arrays.asList("one", "two", "three","four","five"));
map2.put("Column3", Arrays.asList("three"));
map2.put("Column4", Arrays.asList("one", "two","three"));
map2.put("Column5", Arrays.asList("one", "two","three"));
现在创建一个集合,其中包含两个地图的所有键。排序不是必需的,但可以更轻松地与数据进行比较。
SortedSet<String>keySet = new TreeSet<>(map1.keySet());
keySet.addAll(map2.keySet());
- 首先,通过创建一个空列表来防止空列表(对于丢失的键)。
- 遍历列表,比较相同键的值。
- 如果不同,调用辅助方法获取不同的索引
- 显示信息。
for (String key : keySet) {
List<String>list1 = Objects.requireNonNullElse(map1.get(key), List.of());
List<String>list2 = Objects.requireNonNullElse(map2.get(key), List.of());
if (!list1.equals(list2)) {
int[] diffs = getIndices(list1,list2);
System.out.printf("Maps different at key '%s', element(s) %s", key, diffs[0]);
for (int i = 1; i < diffs.length; i++) {
System.out.printf(", %s", diffs[i]);
}
System.out.println();
}
}
以上打印
Maps different at key 'Column1', element(s) 2
Maps different at key 'Column2', element(s) 2, 3, 4
Maps different at key 'Column3', element(s) 1
Maps different at key 'Column5', element(s) 0, 1, 2
Maps different at key 'Column6', element(s) 0, 1
辅助方法。
- 计算列表的最小和最大大小
- 流式传输最大列表的索引。
- 如果索引在两个列表范围内,则进行比较
- 如果比较不同,就传索引
- 如果索引超出范围,则通过它,因为它会标记缺少的列表项。
- 然后return索引数组
public static <T> int[] getIndices(List<T> list1,
List<T> list2) {
int min = Math.min(list1.size(), list2.size());
int max = Math.max(list1.size(), list2.size());
int[] diffs = IntStream.range(0, max)
.filter(i -> i >= min || !list1.get(i).equals(list2.get(i)))
.toArray();
return diffs;
}
我有两个 Map
Map<String, List<String>> map1 = new TreeMap<>();
Map<String, List<String>> map2 = new TreeMap<>();
map1.put("Column1", Arrays.asList("one", "two", "four"));
map1.put("Column2", Arrays.asList("one", "two", "four"));
map2.put("Column1", Arrays.asList("one", "two", "three"));
map2.put("Column2", Arrays.asList("one", "two", "three"));
比较后,结果应该是这样的:“键 1 的值不同,元素 3。键 2 的值不同,元素 3”。我如何遍历两个给定的映射,以便获得不同元素的相应索引?我尝试从每个 Map 创建一个 flatMap,但随后我丢失了列表之间不同元素的 keySet。
有很多方法可以进行比较(例如顺序很重要?如果不是,请使用 Set
而不是 List
)。
比较“不同元素对应索引”的一种方法是:
Map<String, List<String>> diffs = Streams.concat(xs.keySet().stream(), ys.keySet().stream())
.distinct()
.collect(toMap(k -> k, k -> {
List<String> x = xs.getOrDefault(k, emptyList());
List<String> y = ys.getOrDefault(k, emptyList());
return IntStream.range(0, Math.max(x.size(), y.size()))
.mapToObj(i -> i < x.size() ? (i < y.size() ? (x.get(i).equals(y.get(i)) ? "=": "<>"): "X") : "Y")
.collect(toList());
}));
如果索引 i
处的元素相等,则得到 =
,如果不同,则得到 <>
,如果该索引存在,则得到 X
或 Y
只有一套。
例如:
xs.put("Column1", Arrays.asList("one", "xxx", "four"));
xs.put("Column2", Arrays.asList("one", "two"));
xs.put("Column3", Arrays.asList("cat"));
ys.put("Column1", Arrays.asList("one", "two", "four"));
ys.put("Column2", Arrays.asList("one", "two", "three"));
ys.put("Column4", Arrays.asList("apple"));
有输出
{ Column1=[=, <>, =]
, Column2=[=, =, Y]
, Column3=[X]
, Column4=[Y]
}
这是一种方法。在不知道数据的性质的情况下,至少提及边界情况很重要。
- 首先,你的例子暗示你在做位置差异。所以
"one","two"
与"two","one"
不同,因此被标记为elements 0, 1
不同。 - 地图可能有不同的键。这意味着对于任何给定的键,缺少该键的映射内容都是不同的。
- 对应键的列表可能有不同数量的元素。前几个可能是一样的。任何元素缺失而不仅仅是不同的元素都会被标记出来。
这是数据
Map<String, List<String>> map1 = new TreeMap<>();
Map<String, List<String>> map2 = new TreeMap<>();
map1.put("Column1", Arrays.asList("one", "two", "four"));
map1.put("Column2", Arrays.asList("one", "two", "four"));
map1.put("Column3", Arrays.asList("three", "two"));
map1.put("Column4", Arrays.asList("one","two","three"));
map1.put("Column6", Arrays.asList("nine","ten"));
map2.put("Column1", Arrays.asList("one", "two", "three"));
map2.put("Column2", Arrays.asList("one", "two", "three","four","five"));
map2.put("Column3", Arrays.asList("three"));
map2.put("Column4", Arrays.asList("one", "two","three"));
map2.put("Column5", Arrays.asList("one", "two","three"));
现在创建一个集合,其中包含两个地图的所有键。排序不是必需的,但可以更轻松地与数据进行比较。
SortedSet<String>keySet = new TreeSet<>(map1.keySet());
keySet.addAll(map2.keySet());
- 首先,通过创建一个空列表来防止空列表(对于丢失的键)。
- 遍历列表,比较相同键的值。
- 如果不同,调用辅助方法获取不同的索引
- 显示信息。
for (String key : keySet) {
List<String>list1 = Objects.requireNonNullElse(map1.get(key), List.of());
List<String>list2 = Objects.requireNonNullElse(map2.get(key), List.of());
if (!list1.equals(list2)) {
int[] diffs = getIndices(list1,list2);
System.out.printf("Maps different at key '%s', element(s) %s", key, diffs[0]);
for (int i = 1; i < diffs.length; i++) {
System.out.printf(", %s", diffs[i]);
}
System.out.println();
}
}
以上打印
Maps different at key 'Column1', element(s) 2
Maps different at key 'Column2', element(s) 2, 3, 4
Maps different at key 'Column3', element(s) 1
Maps different at key 'Column5', element(s) 0, 1, 2
Maps different at key 'Column6', element(s) 0, 1
辅助方法。
- 计算列表的最小和最大大小
- 流式传输最大列表的索引。
- 如果索引在两个列表范围内,则进行比较
- 如果比较不同,就传索引
- 如果索引超出范围,则通过它,因为它会标记缺少的列表项。
- 然后return索引数组
public static <T> int[] getIndices(List<T> list1,
List<T> list2) {
int min = Math.min(list1.size(), list2.size());
int max = Math.max(list1.size(), list2.size());
int[] diffs = IntStream.range(0, max)
.filter(i -> i >= min || !list1.get(i).equals(list2.get(i)))
.toArray();
return diffs;
}