groupingBy将多个数据库记录映射到具有List

groupingBy将多个数据库记录映射到具有List

本文介绍了如何使用Java 8 Streams groupingBy将多个数据库记录映射到具有List< String>的单个对象一栏的财产的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题基本上归结为这个简化的例子。我从数据库返回的数据在行中有一些重复的信息。

My problem essentially comes down to this simplified example. I have data coming back from a DB which has some duplicate information in the rows.

在这个例子中,我有一个从数据库返回的 TeamRow 对象的列表。我可以使用 Collectors.groupingBy 轻松地对这些进行分组:

In this example I have a list of TeamRow objects that come back from the DB. I can easily group these using Collectors.groupingBy:

public class TeamRow {
    private int id;
    private String name;
    private String player;

    public TeamRow(int id, String name, String player) {
        this.id = id;
        this.name = name;
        this.player = player;
    }

    public int getId() {return id;}
    public String getName() { return name; }
    public String getPlayer() {return player;}
}

public class Team {
    private int id;
    private String name;
    private List<String> players;

    public Team(int id, String name, List<String> players) {
        this.id = id;
        this.name = name;
        this.players = new ArrayList<String>(players);
    }
}

List<TeamRow> dbTeams = new ArrayList<TeamRow>();
dbTeams.add(new TeamRow(1, "Team1", "Jonny"));
dbTeams.add(new TeamRow(1, "Team1", "Rob"));
dbTeams.add(new TeamRow(1, "Team1", "Carlos"));
dbTeams.add(new TeamRow(2, "Team2", "Shane"));
dbTeams.add(new TeamRow(2, "Team2", "Lucas"));
dbTeams.add(new TeamRow(3, "Team3", "Geraint"));
dbTeams.add(new TeamRow(3, "Team3", "Rocky"));
dbTeams.add(new TeamRow(3, "Team3", "Wayne"));
dbTeams.add(new TeamRow(3, "Team3", "Dwayne"));
dbTeams.add(new TeamRow(3, "Team3", "Lester"));

Map<Integer, List<TeamRow>> myMap = dbTeams.stream().collect(Collectors.groupingBy(TeamRow::getId));

然而,我实际上想要实现的是转换 TeamRow s到团队 s。因此,id和name只表示一次,并且播放器存储在 Team 对象的List中。我可以通过在地图上添加 forEach 来实现这一点,如下所示。

However, what I'm actually trying to achieve is to convert the TeamRows to Teams. So that the id and name are only represented once and the players are stored in a List in the Team object. I can achieve this by adding a forEach over the map as shown below.

但我一直在尝试弄清楚是否有一种方法可以通过添加某种映射器或下游收集器来实现相同的结果。这甚至可以提供任何好处,而不是添加后续 forEach ??例如:

But I've been trying to figure out if there is a way I can achieve the same result by adding some sort of mapper or downstream collector. Would this even offer any benefit over adding a subsequent forEach ?? Eg:

List<Team> teams = dbTeams.stream().collect(Collectors.groupingBy(TeamRow::getId, ???), ???).???;

使用forEach进行转换:

Conversion using forEach:

List<Team> teams = new ArrayList<>();
myMap.forEach((id, teamRows) -> {
    if (teamRows.size() > 0) {
        TeamRow tr = teamRows.get(0);
        List<String> players = teamRows.stream().map(TeamRow::getPlayer).collect(Collectors.toList());
        teams.add(new Team(id, tr.getName(), players));
    }
});


推荐答案

您可以使用收集器。将 merge 方法添加到团队类可能是个好主意:

You may use toMap collector with custom merge function. It's probably a good idea to add merge method to the Team class:

public class Team {
    private final int id;
    private final String name;
    private final List<String> players;

    public Team(int id, String name, List<String> players) {
        this.id = id;
        this.name = name;
        this.players = new ArrayList<>(players);
    }

    // merges other team into this team, returning this team
    public Team merge(Team other) {
        assert id == other.id; // remove asserts if you don't like them
        assert name.equals(other.name);
        players.addAll(other.players);
        return this;
    }
}

现在你可以通过这种方式解决问题:

Now you can solve your problem this way:

Collection<Team> teams = dbTeams.stream()
        .map(tr -> new Team(tr.id, tr.name, Arrays.asList(tr.player)))
        .collect(Collectors.toMap(t -> t.id, t -> t, Team::merge)).values();

这篇关于如何使用Java 8 Streams groupingBy将多个数据库记录映射到具有List&lt; String&gt;的单个对象一栏的财产的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 02:20