Java 8 Java8流映射自定义函数并将其转换为映射

Java 8 Java8流映射自定义函数并将其转换为映射,java-8,java-stream,collect,Java 8,Java Stream,Collect,我正在使用Java8 我有以下目标: public class Book { private Long id; private Long bookId; private String bookName; private String owner; } 由下表表示: 基本上,一本书可以由多个所有者拥有,即所有者“a”拥有第1和第2本书 我有一个基本函数,当传递一个book对象时,它将在列表中给出它的所有者 private List<String>

我正在使用Java8

我有以下目标:

public class Book {

    private Long id;
    private Long bookId;
    private String bookName;
    private String owner;
}
由下表表示:

基本上,一本书可以由多个所有者拥有,即所有者“a”拥有第1和第2本书

我有一个基本函数,当传递一个book对象时,它将在列表中给出它的所有者

private List<String> getBookToOwner(Book book) {
        List<String> a = new ArrayList<>();
        if (book.getOwner() != null && !book.getOwner().isEmpty()) {
            a.addAll(Arrays.asList(book.getOwner().split("/")));
        }
        return a;
}
私有列表getBookToOwner(图书){
列表a=新的ArrayList();
if(book.getOwner()!=null&&!book.getOwner().isEmpty()){
a、 addAll(Arrays.asList(book.getOwner().split(“/”));
}
返回a;
}
我想用它来应用于每本书,检索它们的所有者并创建以下地图

Map<String, List<Long>> ownerToBookMap;
地图所有者网络地图;
像这样:

我如何在这里使用流

//books is List<Book>
Map<String, List<Long>> ownerToBookMap = books.stream().map( 
// apply the above function to get its owners, flatten it and finally collect it to get the above Map object
// Need some help here..
);
//书籍是列表
Map ownerToBookMap=books.stream().Map(
//应用上述函数获取其所有者,将其展平,最后收集以获取上述地图对象
//这里需要帮助。。
);

我使用
reduce
而不是
map

Map<String, List<Long>> ownerToBookMap = books.stream().reduce(
    HashMap::new,
    (acc,b) -> {
        getBookToOwner(b).stream().forEach( o -> {
            if (!acc.containsKey(o))
                acc.put(o, new ArrayList<Long>());
            acc.get(o).put(b.bookId);
        });
        return acc;
    }
).get();
Map ownerToBookMap=books.stream().reduce(
HashMap::新建,
(行政协调会,b)->{
getBookToOwner(b).stream().forEach(o->{
如果(!acc.CONTANSKEY(o))
acc.put(o,新的ArrayList());
acc.get(o)、put(b.bookId);
});
返回acc;
}
).get();

将所有者映射为一个所有者,创建条目,其中key作为单个
所有者
,value作为
图书ID
。然后按键(
owner
)对结构进行分组。最后使用
Collectors::mapping
获取
bookId
s的
列表,而不是实际条目:

List<Book> books = ...

Map<String, List<Long>> booksByOwner = books.stream()
    .flatMap(book -> Arrays.stream(book.getOwner().split("/"))
             .map(owner -> new AbstractMap.SimpleEntry<>(owner, book.getBookId())))
    .collect(Collectors.groupingBy(
             AbstractMap.SimpleEntry::getKey, 
             Collectors.mapping(AbstractMap.SimpleEntry::getValue, Collectors.toList())));
列出书籍=。。。
Map booksByOwner=books.stream()
.flatMap(book->Arrays.stream(book.getOwner().split(“/”))
.map(所有者->新建AbstractMap.SimpleEntry(所有者,book.getBookId()))
.collect(收集器.groupingBy(
AbstractMap.SimpleEntry::getKey,
Collectors.mapping(AbstractMap.SimpleEntry::getValue,Collectors.toList());

您可以从书中获取所有者列表,然后使用
flatMap
将所有者和地图作为
bookId
owner
的一对展开。然后使用
groupingBy
owner
分组,并收集
owner
bookId
列表

Map<String, List<Long>> ownerToBookMap = 
     books.stream()
          .flatMap(b -> getBookToOwner(b)
                         .stream()
                         .map(o -> new AbstractMap.SimpleEntry<>(o, b.getBookId())))
          .collect(Collectors.groupingBy(Map.Entry::getKey,
                     Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
Map ownerToBookMap=
books.stream()
.flatMap(b->getBookToOwner(b)
.stream()
.map(o->newAbstractMap.SimpleEntry(o,b.getBookId()))
.collect(Collectors.groupingBy(Map.Entry::getKey、,
Collectors.mapping(Map.Entry::getValue,Collectors.toList());

因此,例如,如果一本书有三个所有者,您可以创建三个独立的
book
对象,其中每个
book
正好有一个所有者。然后可以执行
groupingBy
,因为每本
Book
只有一个所有者。这不是很昂贵吗(就时间和资源而言)?实际上,垃圾收集器几乎会立即消耗这些短期对象。您可以使用
AbstractMap.SimpleEntry
来代替。@Abra抱歉,错过了一些东西。。我刚刚更新了答案。我在尝试第一个选项时遇到了一些错误。后来我使用了@Rono提供的上述解决方案,这很有效。只是一个建议:不要在一个列中包含多个值(在您的案例中是所有者列)。因此,为了修复它,我建议您与所有者表创建多对多关系。在这种情况下,将创建一个中间映射表。请在线查看更多详细信息。