Java流,获取对象列表的映射

时间:2019-12-10 00:17:53

标签: java java-8 java-stream

尝试使用Java 8获取列表的地图。我有一组预定义的标题:

String[] myStringArray = {"TITLE1", "TITLE2", "TITLE3"};

以及一些Pages对象(List<String>)的列表。

如果在页面上找到该数组的值,则需要使用预定义数组的键创建一个对象列表的映射。结果应为:

{TITLE1=[page1, page2, page3], TITLE2=[page3, page4, page5]} 

(假设在页面列表中未找到TITLE3)

我的代码:

Arrays.stream(myStringArray)
        .map(title -> page
                .stream()
                .filter(p -> isPageContainsTitle(p, title))
                .collect(Collectors.toList()))
        .filter(Objects::nonNull)
        .collect(Collectors.toMap(e->e, Function.identity()));

结果,我得到了键列表中的列表列表,而不是myStringArray中的值:

{[page1, page2, page3]=[page1, page2, page3], [page3, page4, page5]=[page3, page4, page5]} 

4 个答案:

答案 0 :(得分:3)

只需确保数组具有唯一的标题,然后使用Collectors.toMap

Map<String, List<String>> result = Arrays.stream(myStringArray)
            .map(title -> new AbstractMap.SimpleEntry<>(title,
                    pages.stream().filter(page -> isPageContainsTitle(page,title)).collect(Collectors.toList())))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

按照@Naman的建议,您可以避免进行中间的map操作

Map<String, List<String>> result = Arrays.stream(myStringArray) 
                     .collect(Collectors.toMap(Function.identity() 
                                        ,title -> pages.stream()
                                                       .filter(page -> isPageContainsTitle(page, title))
                                                       .collect(Collectors.toList())));

答案 1 :(得分:2)

下面的代码应该对您有用:

package com.shree.test;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class StreamTest {
    public static void main(String[] args) {
        String[] myStringArray = {"TITLE1", "TITLE2", "TITLE3"};
        List<String> pages = new ArrayList<>();
        pages.add("TEXT,TITLE2,TEXT,ONE,TWO");
        pages.add("TEXT,TITLE1,TEXT,ONE,TWO");
        pages.add("TEXT,TITLE2,TEXT,ONE,TWO");
        pages.add("TEXT,TITLE2,TEXT,TITLE3,TWO");
        pages.add("TEXT,TITLE3,TEXT,ONE,TWO");



         Map<Object, Object> titleMap = getTitleMap(myStringArray, pages);

         titleMap.entrySet().forEach(System.out::println);
    }

    private static Map<Object, Object> getTitleMap(String[] myStringArray, List<String> pages) {
        Map<Object, Object> titleMap = Arrays.asList(myStringArray).stream()
            .map(
                    (title)->{
                        return new AbstractMap.SimpleEntry<>(title, pages.stream()
                                .filter((page)->page.contains(title))
                                .collect(Collectors.toList()));
                    }
                )
            .collect(Collectors.toMap(entry->entry.getKey(), entry->entry.getValue()));
        return titleMap;
    }
}

答案 2 :(得分:0)

所以

 e->e

  Function.identity()

是并且应该等效。

您真正想要的是flatMap:

  Arrays.stream(myStringArray)
                .flatMap(title -> pages
                        .stream()
                        .filter(p -> isPageContainsTitle(p, title))
                        .map( p -> new Tuple(t, p)) 
                 )
                 .collect(Collectors.groupingBy( t -> t._1, t -> t._2));

我们想要flatMap,因为我们可能会返回0、1或许多元组的(标题,页面)

这假设您有一个Tuple类,我正在基于Scala的Tuple2建模一个类。

注意,我尚未测试此代码。

答案 3 :(得分:0)

我看到的唯一方法是使用单独的对象将其映射到类型为StringList<Page>的两个元素数组到数组,然后使用这些条目构建映射

Object[]{}数组将包含标题和列表。这是在嵌套流中保留两个值的唯一方法。

我后来将它们投射成一个Map<String,List<Page>>

这不需要修改您现有的数据结构。

 Map<String, List<Page>> map = Arrays.stream(myStringArray)
            .map((String title) -> new Object[] {title,
                                       page.stream().filter(
                                   (Page p) -> isPageContainsTitle(p, title)).collect(
                                    Collectors.toList())})
            .filter(arr->arr[1] != null)
            .collect(Collectors.toMap(arr -> (String)arr[0], arr -> (List<Page>)arr[1]));

最终的List强制转换中有类型安全警告,但应该没问题。