java - 按 Java Streams 中的字段分组

标签 java java-8 java-stream

所以,我有一个如下所示的输入 JSON:

[{
  "added": "2014-02-01T09:13:00Z",
  "author": {
    "id": "1",
    "name": "George R R Martin",
    "added_on": "2013-02-01T09:13:00Z"
  },
  "book": {
    "id": "12",
    "name": "Game of Thrones",
    "genre": "Fantasy Fiction"
  }
},
{
  "added": "2015-02-01T09:13:00Z",
  "author": {
    "id": "2",
    "name": "Patrick Rothfuss",
    "added_on": "2012-09-13T011:40:00Z"
  },
  "book": {
    "id": "15",
    "name": "The Name of the Wind",
    "genre": "Fantasy Fiction"
  }
}, {
  "added": "2016-02-01T09:13:00Z",
  "author": {
    "id": "2",
    "name": "Patrick Rothfuss",
    "added_on": "2012-09-13T011:40:00Z"
  },
  "book": {
    "id": "17",
    "name": "The Wise Man's Fear",
    "genre": "Fantasy Fiction"
  }
}]

我需要根据 author.id 对其进行分组。一位作者将拥有一个对象和他所创作的所有书籍的列表。 这是我期望的输出:

[
  {
    "author": "George R R Martin",
    "added_on": "2013-02-01T09:13:00Z",
    "books": [
      {
        "book_name": "Game of Thrones",
        "added": "2014-02-01T09:13:00Z"
      }
    ]
  },
  {
    "author": "Patrick Rothfuss",
    "added_on": "2012-09-13T011:40:00Z",
    "books": [
      {
        "book_name": "The Name of the Wind",
        "added": "2015-02-01T09:13:00Z"
      }, {
        "book_name": "The Wise Man's Fear",
        "added": "2016-02-01T09:13:00Z"
      }
    ]
  }
]

我尝试通过一个普通的 for 循环来完成它——它有效。但是,只是为了更多地了解 Streams,我想尝试使用 Streams。

我试过这个:

Map<Author, List<Book>> collect = authorsList.stream()
                .collect(Collectors.groupingBy(AuthorBookObj::getAuthor,
                        Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));

但是,没有得到我需要的东西。相反,它创建了三个 map 而不是两个。

也试过这个:

Map<AuthorTuple, List<Book>> collect = authorsList.stream()
                .collect(Collectors.groupingBy(authors -> new AuthorTuple(authors.getAuthor().getId(),
                                authors.getAuthor().getName(), authors.getAuthor().getAddedOn()),
                        Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));

它还为我提供了列表中的三个对象。我希望有两位作者和每位作者对应的书籍。

AuthBookObj:

public class AuthorBookObj
{

    private String id;

    private Author author;

    private Book book;

    private String added;
    //getter, setter
}

public class Article
{
    private String name;

    private String id;

    private String genre;
}


public class Author
{
    private String name;

    private String added_on;

    private String id;
}

最佳答案

问题不在于您处理流的方式,而在于对象的相等性。

正确的方法是使用这段代码:

Map<Author, List<Book>> collect = authorsList.stream()
                .collect(Collectors.groupingBy(AuthorBookObj::getAuthor,
                        Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));

但现在您正在比较 Author 对象,因为对象不同,您会得到三个条目。您需要在 Author 对象中添加一个 hashcode 和 equals 来比较作者 ID 上的对象。

//code generated from intellij. 
// Author.java
 @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Author author = (Author) o;
        return getId() == author.getId();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId());
    }

关于java - 按 Java Streams 中的字段分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54488138/

相关文章:

Java 8 分组依据的逆向

java - 空检查后抛出空错误?

java-8 - 流 : "cannot convert Comparator to int" when using method reference

java - 为什么 Java 说这些类型不兼容?

java - 将数组迭代转换为 lambda 表达式

java - 您可以在不映射到字符串的情况下收集(joining())吗?

java - 如何让 ExecutorService 中的线程进入等待阶段

java - 如何在Optaplanner的coursecourse XML文件中设置积极的软约束(奖励)

java - MongoDB 3.3.0以上版本中QueryBuilder和BasicDBObjectBuilder的使用

java - 如何将 View 更改为 JTree?