简体   繁体   English

将 java 7 嵌套 for 循环转换为使用 java 8 流 API

[英]converting java 7 nested for loops to use java 8 streams API

I have an example here which basically returns list based on simple logic我这里有一个例子,它基本上根据简单的逻辑返回列表

Given an input list and a list of grouping objects, which has a list field, the method should return a list that contains either all the members of grouping.list if the grouping.name matches any of the strings in the input list OR simply add the input string to the returning list.给定一个输入列表和一个具有列表字段的分组对象列表,如果grouping.name匹配输入列表中的任何字符串,该方法应该返回一个包含grouping.list所有成员的列表,或者简单地添加返回列表的输入字符串。

After I writing this code, I am thinking it could be made simpler in Java 7 and a better example to use Java 8 Streaming API.在我编写这段代码之后,我认为它可以在 Java 7 中变得更简单,并且是使用 Java 8 Streaming API 的更好示例。

public class CollectorExample {

    public static void main(String[] args){

        List<String> input = new ArrayList<>();
        input.add("foo");
        input.add("bar");
        input.add("foobar");
        input.add("java");

        List<String> list1 = new ArrayList<>();
        list1.add("hello");
        list1.add("world");

        List<String> list2 = new ArrayList<>();
        list2.add("spring");
        list2.add("multi-threaded");


        Grouping g1 = new Grouping("foobar",list1);
        Grouping g2 = new Grouping("java",list2);

        List<Grouping> groupingList = new ArrayList<>();
        groupingList.add(g1);
        groupingList.add(g2);


        System.out.println(mapAndMerge(input,groupingList));


    }


    public static List<String> mapAndMerge(List<String> input, List<Grouping> groupingList){

        Set<String> returnDocs = new HashSet<>();
        Iterator<String> it = input.iterator();
        while(it.hasNext()){
            String doc = it.next();
            boolean found = false;
            for (Grouping lg : groupingList){
                if (lg.getName().equals(doc)){
                    returnDocs.addAll(lg.getList());
                    found=true;
                   }
                }
            if (!found){
                returnDocs.add(doc);
            }
        }
    return new ArrayList<>(returnDocs);
    }

}

class Grouping {

    List<String> list;
    String name;

    public Grouping(String name, List<String> list){
        this.list=list;
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }


}

This outputs [spring, bar, world, foo, hello, multi-threaded] which is correct.这输出[spring, bar, world, foo, hello, multi-threaded]这是正确的。 Here is my Java 8 syntax that I tried and did NOT work;这是我尝试过但没有用的 Java 8 语法;

//        List<String> mergedDocs = 
//                input.forEach(doc->
//                                 groupingList.stream().map( g -> g.getName().equals(doc) ? e.getList() : doc ).collect(Collectors.toList()));
//        return mergedDocs;

You can make this a lot simpler by not using your Grouping class but using a simple Map<String, List<String>> instead.您可以通过不使用使这个简单了很多Grouping类,但用一个简单的Map<String, List<String>>代替。 This map would act as the grouping, holding the list for a given name.该地图将作为分组,保存给定名称的列表。 This also enables to have a much better performance since looking into the map is constant-time (whereas your solution is in linear time since it traverses the grouping to find a matching one).这也使性能更好,因为查看地图是恒定时间的(而您的解决方案是线性时间,因为它遍历分组以找到匹配的一个)。

If you have to use the List<Grouping> , you can still pre-process it to convert into an intermediate Map :如果您必须使用List<Grouping> ,您仍然可以对其进行预处理以将其转换为中间Map

The mapAndMerge method simply becomes: mapAndMerge方法简单地变为:

public static List<String> mapAndMerge(List<String> input, List<Grouping> groupingList) {
    Map<String, List<String>> map = groupingList.stream().collect(Collectors.toMap(Grouping::getName, Grouping::getList));
    return input.stream()
                .flatMap(s -> map.getOrDefault(s, Arrays.asList(s)).stream())
                .collect(Collectors.toList());
}

Each input is flat mapped to the list contained in the map or a default list containing the current element.每个输入都平面映射到映射中包含的列表或包含当前元素的默认列表。 Then this is collected to a new list.然后将其收集到一个新列表中。 This code prints:此代码打印:

[foo, bar, hello, world, spring, multi-threaded]

You can re-write the mapAndMerge method following way using java 8. But it is not very concise as you like.您可以使用 java 8 按照以下方式重新编写mapAndMerge方法。但它不是您喜欢的很简洁。

    public static List<String> mapAndMerge(List<String> input,
        List<Grouping> groupingList) {

      Set<String> returnDocs = input
        .stream()
        .map(t -> groupingList
            .stream()
            .filter(g -> g.getName().equals(t))
            .map(v -> v.getList())
            .findAny()
            .orElse(Arrays.asList(t)))
        .flatMap(t -> t.stream())
        .collect(Collectors.toSet());

      return new ArrayList<>(returnDocs);
    }

I think it would be much simple and clearer if you use Map instead of the Grouping class.我认为如果您使用Map而不是Grouping类会更简单明了。

So that's what you'll have in the main() method:这就是 main() 方法中的内容:

    Map<String, List<String>> groupingMap = new HashMap<>();
    groupingMap.put("foobar", list1);
    groupingMap.put("java", list2);

    List<String> mergedDocs = new ArrayList<>();
    input.stream()
         .map(doc -> groupingMap.getOrDefault(doc, Collections.singletonList(doc)))
         .forEach(mergedDocs::addAll);

    System.out.println(mergedDocs);

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

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