简体   繁体   English

Java 8 Streams:如何匹配两个 ArrayList 字符串之间的值并创建另一个 object 的列表

[英]Java 8 Streams: How to match values between two ArrayList of Strings and create a list of another object

I am having two lists of Strings and want to compare the values in the lists and construct a new list of another object. I am able to do this with nested loops but looking for a more performant and neater solution.我有两个字符串列表,想比较列表中的值并构建另一个 object 的新列表。我可以使用嵌套循环来做到这一点,但正在寻找一种性能更高、更简洁的解决方案。

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

There is a Vehicle object.有一辆车辆 object。

class Vehicle {

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

Now, I need to build the vehicle object using by matching the model (the first character from list1) with the first character in list2 and build something like this现在,我需要通过将 model(list1 中的第一个字符)与 list2 中的第一个字符匹配来构建车辆 object,并构建类似这样的东西

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

Can the nested loop be avoided by using streams?使用流可以避免嵌套循环吗?

I'd follow an approach like the following:我会遵循如下方法:

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

The data as provided.所提供的数据。

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

Regardless of how the model type information is obtained, this conversion might be more efficient and certainly easier if instead of using Lists you used Maps to hold the information.不管 model 类型信息是如何获得的,如果不使用Lists而使用Maps来保存信息,这种转换可能会更有效,当然也更容易。 If the information was read in from a file it would be best to pre-process them (split if need be) as they are read in and put them in a map. If it was entered by hand then putting the information in a map would negate the need for any pre-processing at all.如果信息是从文件中读入的,最好在读入时对它们进行预处理(如果需要则拆分)并将它们放入 map 中。如果是手动输入,则将信息放入 map 中完全不需要任何预处理。 Here is a simple example.这是一个简单的例子。

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

However, using the information as provided here is how I proceeded.但是,使用此处提供的信息是我进行的方式。

First, I created a Lambda to assist in the List conversion.首先我创建了一个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);

Now just use the keysets of each to go thru and piece it together.现在只需使用每个到 go 的键集并将它们拼凑在一起。 I created a constructor in my example for Vehicle which imho makes a cleaner object creation.我在我的Vehicle示例中创建了一个构造函数,恕我直言,它创建了一个更干净的 object 。

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

Prints based on toString (which can be changed).基于 toString 打印(可以更改)。

[Airplane, Boeing Airplane,A,A90]
[Airplane, Boeing777,A,A70]
[Boat, Boeing Boat,B,B80]

Here is the class sans setters and getters.这是 class sans setters 和 getters。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM