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

时间:2016-02-04 19:19:52

标签: java collections iterator java-8 java-stream

我这里有一个例子,基本上是基于简单的逻辑

返回列表

给定一个输入列表和一个具有列表字段的分组对象列表,如果grouping.list匹配任何字符串,该方法应返回包含grouping.name所有成员的列表在输入列表中或只是将输入字符串添加到返回列表中。

在编写此代码之后,我认为在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;
    }


}

这输出正确的[spring, bar, world, foo, hello, multi-threaded]。 这是我尝试过但不起作用的Java 8语法;

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

3 个答案:

答案 0 :(得分:2)

您可以通过不使用Grouping类,而是使用简单的Map<String, List<String>>来简化 。此映射将充当分组,保存给定名称的列表。这也可以提供更好的性能,因为查看地图是恒定时间(而您的解决方案是在线性时间内,因为它遍历分组以找到匹配的一个)。

如果您必须使用List<Grouping>,您仍然可以预处理它以转换为中间Map

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

每个输入都平面映射到地图中包含的列表或包含当前元素的默认列表。然后将其收集到新列表中。此代码打印:

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

答案 1 :(得分:1)

您可以使用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);
    }

答案 2 :(得分:0)

如果您使用Map代替Grouping类,我认为会更加简单明了。

这就是你在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);