当前位置: 首页 > 知识库问答 >
问题:

Java8 Streams:如何匹配两个ArrayList的字符串之间的值,并创建另一个对象的列表

涂羽
2023-03-14

我有两个字符串列表,希望比较列表中的值并构造另一个对象的新列表。我可以用嵌套循环来实现这一点,但我正在寻找一种更高效、更整洁的解决方案。

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");

有一个车辆物体。

class Vehicle {

private String model;
private String submodel;
private String type;
private String subtype;
// setters getters
}

现在,我需要通过匹配模型(列表1中的第一个字符)和列表2中的第一个字符来构建车辆对象,并构建这样的东西

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;
    }

使用流可以避免嵌套循环吗?

共有2个答案

梁丘威
2023-03-14

提供的数据。

List<String> list1 = new ArrayList<>();
list1.add("A,Airplane");
list1.add("B,Boat");

List<String> list2 = new ArrayList<>();
list2.add("A90, Boeing Airplane");
list2.add("A70, Boeing777");
list2.add("B80, Boeing Boat");

无论模型类型信息是如何获得的,如果您使用Maps来保存信息,而不是使用Lists,这种转换可能会更有效,当然也更容易。如果信息是从文件中读取的,最好在读取时对它们进行预处理(如果需要,拆分),并将它们放在地图中。如果是手工输入的,那么将信息放入地图将完全不需要任何预处理。这里有一个简单的例子。

Map<String,String> map1 = new HashMap<>();
map1.put("A","Airplane");
map1.put("B","Boat");

然而,使用这里提供的信息是我如何进行的。

首先,我创建了一个Lambda来帮助List转换。

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);

现在只需使用每一个键组通过并将其拼合在一起。在我的示例中,我为Vehicle创建了一个构造函数,imho可以更清晰地创建对象。

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,A,A70]
[Boat, Boeing Boat,B,B80]

这是类sans setter和getter。

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, type, subtype)
                + "]";
    }
}

苏野
2023-03-14

我将遵循如下方法:

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());
 类似资料: