问题描述
我有两个字符串列表,想要比较列表中的值并构造另一个对象的新列表。我能够使用嵌套循环来做到这一点,但正在寻找一种更高性能,更整洁的解决方案。
List<String> list1 = new ArrayList();
list1.add("A,Airplane");
list1.add("B,Boat");
List<String> list2 = new ArrayList();
list2.add("A90,Boing Airplane");
list2.add("A70,Boing777");
list2.add("B80,Boing Boat");
有一个Vehicle对象。
class Vehicle {
private String model;
private String submodel;
private String type;
private String subtype;
// setters getters
}
现在,我需要通过将模型(list1中的第一个字符)与list2中的第一个字符进行匹配来构建车辆对象,并构建类似这样的东西
private List<Vehicle> buildVehicle(List<String> list1,List<String> list2) {
List<Vehicle> vehicles = new ArrayList<>();
if (ObjectUtils.isNotEmpty(list2)) {
list2.forEach(v -> {
Vehicle vehicle = new Vehicle();
if (v.contains(",")) {
String[] val = StringUtils.split(v,",");
vehicle.setSubtype(val[0]);
vehicle.setSubmodel(val[1]);
}
for (String c : list1) {
//Matching the first character from element in list1
if (c.substring(0,1).equals(vehicle.getSubtype().substring(0,1))
&& c.contains(",")) {
String[] val = StringUtils.split(c,");
vehicle.setType(val[0]);
vehicle.setModel(val[1]);
}
break;
}
}
vehicles.add(vehicle);
});
}
return vehicles;
}
是否可以通过使用流来避免嵌套循环?
解决方法
我将遵循以下方法:
List<String> list1 = new ArrayList<>();
list1.add("A,Airplane");
list1.add("B,Boat");
List<String> list2 = new ArrayList<>();
list2.add("A90,Boing Airplane");
list2.add("A70,Boing777");
list2.add("B80,Boing Boat");
Pattern commaPattern = Pattern
.compile("\\s*,\\s*"); // a regex pattern to split by comma and the whitespace around it
Map<String,String> modelToType = list1.stream().map(commaPattern::split)
.collect(Collectors
.toMap(modelAndType -> modelAndType[0],modelAndType -> modelAndType[1])); // mapping models to types for o(1) lookups
List<Vehicle> vehicles = list2.stream().map(commaPattern::split)
.map(subModelAndSubType -> {
Vehicle vehicle = new Vehicle();
vehicle.submodel = subModelAndSubType[0];
vehicle.subtype = subModelAndSubType[1];
vehicle.model = vehicle.submodel.substring(0,1);
vehicle.type = modelToType.get(vehicle.model);
return vehicle;
}).collect(Collectors.toList());
,
提供的数据。
List<String> list1 = new ArrayList<>();
list1.add("A,Boeing Airplane");
list2.add("A70,Boeing777");
list2.add("B80,Boeing Boat");
无论如何获取模型类型信息,如果您不是使用Lists
来保存信息,而是使用Maps
来进行转换,此转换可能会更加高效,当然也更容易。如果从文件中读取了信息,则最好在读取文件时对其进行预处理(如果需要,则进行拆分)并将其放入地图中。如果是手工输入的,那么将信息放在地图中将根本不需要任何预处理。这是一个简单的例子。
Map<String,String> map1 = new HashMap<>();
map1.put("A","Airplane");
map1.put("B","Boat");
但是,请按照此处提供的信息进行操作。
首先,我创建了一个Lambda来协助列表转换。
Function<List<String>,Map<String,String>> makeMap =
lst -> lst.stream().map(st -> st.split("\\s*,\\s*")).collect(
Collectors.toMap(a -> a[0],a -> a[1]));
// create the TypeModel map
Map<String,String> mapTM = makeMap.apply(list1);
// create the subTypeSubModel Map;
Map<String,String> mapSTSM = makeMap.apply(list2);
现在只需使用每个键集将它们组合在一起即可。
我在示例中为imho制作的Vehicle
创建了一个构造函数
更干净的对象创建。
List<Vehicle> vehicles = mapTM.keySet().stream()
.flatMap(type -> mapSTSM.keySet().stream()
.filter(subType -> subType.startsWith(type))
.map(sbType -> new Vehicle(mapTM.get(type),mapSTSM.get(sbType),type,sbType)))
.collect(Collectors.toList());
vehicles.forEach(System.out::println);
基于toString进行打印(可以更改)。
[Airplane,Boeing Airplane,A,A90]
[Airplane,Boeing777,A70]
[Boat,Boeing Boat,B,B80]
这是班级的无用者和吸气剂。
class Vehicle {
private String model;
private String submodel;
private String type;
private String subtype;
public Vehicle() {
}
public Vehicle(String model,String submodel,String type,String subtype) {
this.model = model;
this.submodel = submodel;
this.type = type;
this.subtype = subtype;
}
public String toString() {
return "[" + String.join(",",model,submodel,subtype)
+ "]";
}
}