通过映射列表中的键查找值
Find a value by the key in a List of Maps
我有一个 list of maps List<Map<String,String>> input
.
可以用以下方式表示:
[{AddressField=AddressUsageType, AddressValue=PRINCIPAL},
{AddressField=StreetNumber, AddressValue=2020},
{AddressField=StreetName, AddressValue=Some street}]
我想获得特定 AddressField
的 AddressValue
。
例如,我想为 key "AddressUsageType"
获取 value "PRINCIPAL"
。
我已经尝试使用 过滤器 和许多其他 MAP 函数,但最终无法找到合适的解决方案。
这是我获取第一个键值对值的代码片段:
DataTable table;
List<Map<String,String>> input= table.asMaps(String.class, String.class);
String AddressField = input.get(0).get("AddressField");
String AddressValue = input.get(0).get("AddressValue");
System.out.println("AddressField " +AddressField);
System.out.println("AddressValue " +AddressValue);
以上代码段的输出如下:
AddressField AddressUsageType
AddressValue PRINCIPAL
您对地图的使用在这里有点奇怪,因为您的实际键“AddressUsageType”是地图内部的一个值,而每个地图只是存储在静态键后面的一对键和值。如果你不能改变它,你可以用这样的东西:
String key = "AddressUsageType";
String result = "";
for (Map<String,String> map : input)
{
if (map.containsValue(key))
{
result = map.get("AddressValue");
break;
}
}
System.out.println(key + " is " + result);
我想这就是您要找的:
Map<String, String> map = data.stream()
.filter(m -> m.values().contains("AddressUsageType"))
.findFirst()
.orElse(null);
if (map != null) {
System.out.println("AddressField " + map.get("AddressField"));
System.out.println("AddressValue " + map.get("AddressValue"));
}
这里还有一个测试主
public class Test {
public static void main(String[] args) {
List<Map<String, String>> data = new ArrayList<>();
Map<String, String> map1 = new HashMap<>();
map1.put("AddressField", "AddressUsageType");
map1.put("AddressValue", "PRINCIPAL");
data.add(map1);
Map<String, String> map2 = new HashMap<>();
map2.put("AddressField", "StreetNumber");
map2.put("AddressValue", "2020");
data.add(map2);
Map<String, String> map3 = new HashMap<>();
map3.put("AddressField", "StreetName");
map3.put("AddressValue", "Some street");
data.add(map3);
Map<String, String> map = data.stream()
.filter(m -> m.values().contains("AddressUsageType"))
.findFirst()
.orElse(null);
if (map != null) {
System.out.println("AddressField " + map.get("AddressField"));
System.out.println("AddressValue " + map.get("AddressValue"));
}
}
}
输出
过滤输入以仅保留包含 AddressField=AddressUsageType
的地图。然后使用 .map
函数提取 AddressValue
条目并将它们收集到结果列表中。
public static void main(String[] args) {
List<Map<String, String>> input = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("AddressField", "AddressUsageType");
map.put("AddressValue", "PRINCIPAL");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "StreetNumber");
map.put("AddressValue", "2020");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "StreetName");
map.put("AddressValue", "Some street");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "AddressUsageType");
map.put("AddressValue", "NOT_PRINCIPAL");
input.add(map);
List<String> collect = input.stream().filter(e -> e.get("AddressField").equals("AddressUsageType"))
.map(e -> e.get("AddressValue")).collect(Collectors.toList());
System.out.println(input);
System.out.println(collect);
}
输出为
[{AddressField=AddressUsageType, AddressValue=PRINCIPAL}, {AddressField=StreetNumber, AddressValue=2020}, {AddressField=StreetName, AddressValue=Some street}, {AddressField=AddressUsageType, AddressValue=NOT_PRINCIPAL}]
[PRINCIPAL, NOT_PRINCIPAL]
I would like to get the value of AddressValue from value of
AddressField. For eg.,
I want to get the value "PRINCIPAL"
from the key value "AddressUsageType"
您在这里误用了 Map
。因为每个地图都应该有一组有限的 well-defined 键,每个键在您的域中都有特定的含义。每张地图都代表某种地址。
一旦这些数据在您的域模型中具有特定含义,我们强烈建议您将这些数据分组到一个自定义对象中。
优点是:
- 能够对值使用不同的数据类型,而不是将它们存储为
String
。
- 您不必依赖字符串键。
- 您获得干净 self-explanatory 代码的优势(以防您使用清晰准确的名称)。
我知道它可能是很久以前由其他人开发的代码,或者您可能认为现在存储数据更容易。但是你越是推迟重构,它就变得越昂贵。
通过将对象视为一个集合,您可能会使用深度嵌套的集合,例如地图的地图或地图列表的地图,这会影响代码的可维护性。
如果您选择将数据分组到域 class。
,您将如何处理此任务
为了简洁起见,我会使用Java 16条记录。
public record UserAddress(AddressUsageType addressUsageType, int streetNumber, String streetName) {}
而AddressUsageType
将表示为enum
。如果我理解正确的话,地址类型的数量是有限的,所以 error-prone 将此数据存储为 enum 而不是依赖字符串值会更少,并且也提供了一些额外的机会.
public enum AddressUsageType { PRINCIPAL, OTHER_TYPE }
这就是如何从列表中的每个 UserAddress
对象中提取特定字段,方法是能够从其类型中获益,而不是将它们视为字符串:
public static <T> List<T> getAddressValue(List<UserAddress> addresses,
Function<UserAddress, T> keyExtractor) {
return addresses.stream()
.map(keyExtractor)
.toList(); // available with Java 16 onwards
}
上面显示的方法需要一个 list 地址和一个 function 从地址对象中提取特定的 属性 .
main()
- 演示
public static void main(String[] args) {
List<UserAddress> addresses =
List.of(new UserAddress(AddressUsageType.PRINCIPAL, 71, "greenStreet"),
new UserAddress(AddressUsageType.PRINCIPAL, 83, "purpleStreet"),
new UserAddress(AddressUsageType.OTHER_TYPE, 85, "pinkStreet"));
List<AddressUsageType> addressUsageTypes = getAddressValue(addresses, UserAddress::addressUsageType);
List<Integer> streetNumbers = getAddressValue(addresses, UserAddress::streetNumber);
List<String> streetNames = getAddressValue(addresses, UserAddress::streetName);
System.out.println("AddressUsageTypes:\n" + addressUsageTypes);
System.out.println("StreetNumbers:\n" + streetNumbers);
System.out.println("StreetNames:\n" + streetNames);
}
输出
AddressUsageTypes:
[PRINCIPAL, PRINCIPAL, OTHER_TYPE]
StreetNumbers:
[71, 83, 85]
StreetNames:
[greenStreet, purpleStreet, pinkStreet]
我有一个 list of maps List<Map<String,String>> input
.
可以用以下方式表示:
[{AddressField=AddressUsageType, AddressValue=PRINCIPAL},
{AddressField=StreetNumber, AddressValue=2020},
{AddressField=StreetName, AddressValue=Some street}]
我想获得特定 AddressField
的 AddressValue
。
例如,我想为 key "AddressUsageType"
获取 value "PRINCIPAL"
。
我已经尝试使用 过滤器 和许多其他 MAP 函数,但最终无法找到合适的解决方案。
这是我获取第一个键值对值的代码片段:
DataTable table;
List<Map<String,String>> input= table.asMaps(String.class, String.class);
String AddressField = input.get(0).get("AddressField");
String AddressValue = input.get(0).get("AddressValue");
System.out.println("AddressField " +AddressField);
System.out.println("AddressValue " +AddressValue);
以上代码段的输出如下:
AddressField AddressUsageType
AddressValue PRINCIPAL
您对地图的使用在这里有点奇怪,因为您的实际键“AddressUsageType”是地图内部的一个值,而每个地图只是存储在静态键后面的一对键和值。如果你不能改变它,你可以用这样的东西:
String key = "AddressUsageType";
String result = "";
for (Map<String,String> map : input)
{
if (map.containsValue(key))
{
result = map.get("AddressValue");
break;
}
}
System.out.println(key + " is " + result);
我想这就是您要找的:
Map<String, String> map = data.stream()
.filter(m -> m.values().contains("AddressUsageType"))
.findFirst()
.orElse(null);
if (map != null) {
System.out.println("AddressField " + map.get("AddressField"));
System.out.println("AddressValue " + map.get("AddressValue"));
}
这里还有一个测试主
public class Test {
public static void main(String[] args) {
List<Map<String, String>> data = new ArrayList<>();
Map<String, String> map1 = new HashMap<>();
map1.put("AddressField", "AddressUsageType");
map1.put("AddressValue", "PRINCIPAL");
data.add(map1);
Map<String, String> map2 = new HashMap<>();
map2.put("AddressField", "StreetNumber");
map2.put("AddressValue", "2020");
data.add(map2);
Map<String, String> map3 = new HashMap<>();
map3.put("AddressField", "StreetName");
map3.put("AddressValue", "Some street");
data.add(map3);
Map<String, String> map = data.stream()
.filter(m -> m.values().contains("AddressUsageType"))
.findFirst()
.orElse(null);
if (map != null) {
System.out.println("AddressField " + map.get("AddressField"));
System.out.println("AddressValue " + map.get("AddressValue"));
}
}
}
输出
过滤输入以仅保留包含 AddressField=AddressUsageType
的地图。然后使用 .map
函数提取 AddressValue
条目并将它们收集到结果列表中。
public static void main(String[] args) {
List<Map<String, String>> input = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("AddressField", "AddressUsageType");
map.put("AddressValue", "PRINCIPAL");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "StreetNumber");
map.put("AddressValue", "2020");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "StreetName");
map.put("AddressValue", "Some street");
input.add(map);
map = new HashMap<>();
map.put("AddressField", "AddressUsageType");
map.put("AddressValue", "NOT_PRINCIPAL");
input.add(map);
List<String> collect = input.stream().filter(e -> e.get("AddressField").equals("AddressUsageType"))
.map(e -> e.get("AddressValue")).collect(Collectors.toList());
System.out.println(input);
System.out.println(collect);
}
输出为
[{AddressField=AddressUsageType, AddressValue=PRINCIPAL}, {AddressField=StreetNumber, AddressValue=2020}, {AddressField=StreetName, AddressValue=Some street}, {AddressField=AddressUsageType, AddressValue=NOT_PRINCIPAL}]
[PRINCIPAL, NOT_PRINCIPAL]
I would like to get the value of AddressValue from value of AddressField. For eg.,
I want to get the
value "PRINCIPAL"
from thekey value "AddressUsageType"
您在这里误用了 Map
。因为每个地图都应该有一组有限的 well-defined 键,每个键在您的域中都有特定的含义。每张地图都代表某种地址。
一旦这些数据在您的域模型中具有特定含义,我们强烈建议您将这些数据分组到一个自定义对象中。
优点是:
- 能够对值使用不同的数据类型,而不是将它们存储为
String
。 - 您不必依赖字符串键。
- 您获得干净 self-explanatory 代码的优势(以防您使用清晰准确的名称)。
我知道它可能是很久以前由其他人开发的代码,或者您可能认为现在存储数据更容易。但是你越是推迟重构,它就变得越昂贵。
通过将对象视为一个集合,您可能会使用深度嵌套的集合,例如地图的地图或地图列表的地图,这会影响代码的可维护性。
如果您选择将数据分组到域 class。
,您将如何处理此任务为了简洁起见,我会使用Java 16条记录。
public record UserAddress(AddressUsageType addressUsageType, int streetNumber, String streetName) {}
而AddressUsageType
将表示为enum
。如果我理解正确的话,地址类型的数量是有限的,所以 error-prone 将此数据存储为 enum 而不是依赖字符串值会更少,并且也提供了一些额外的机会.
public enum AddressUsageType { PRINCIPAL, OTHER_TYPE }
这就是如何从列表中的每个 UserAddress
对象中提取特定字段,方法是能够从其类型中获益,而不是将它们视为字符串:
public static <T> List<T> getAddressValue(List<UserAddress> addresses,
Function<UserAddress, T> keyExtractor) {
return addresses.stream()
.map(keyExtractor)
.toList(); // available with Java 16 onwards
}
上面显示的方法需要一个 list 地址和一个 function 从地址对象中提取特定的 属性 .
main()
- 演示
public static void main(String[] args) {
List<UserAddress> addresses =
List.of(new UserAddress(AddressUsageType.PRINCIPAL, 71, "greenStreet"),
new UserAddress(AddressUsageType.PRINCIPAL, 83, "purpleStreet"),
new UserAddress(AddressUsageType.OTHER_TYPE, 85, "pinkStreet"));
List<AddressUsageType> addressUsageTypes = getAddressValue(addresses, UserAddress::addressUsageType);
List<Integer> streetNumbers = getAddressValue(addresses, UserAddress::streetNumber);
List<String> streetNames = getAddressValue(addresses, UserAddress::streetName);
System.out.println("AddressUsageTypes:\n" + addressUsageTypes);
System.out.println("StreetNumbers:\n" + streetNumbers);
System.out.println("StreetNames:\n" + streetNames);
}
输出
AddressUsageTypes:
[PRINCIPAL, PRINCIPAL, OTHER_TYPE]
StreetNumbers:
[71, 83, 85]
StreetNames:
[greenStreet, purpleStreet, pinkStreet]