java - 两个集合的左外连接

标签 java collections

标题中的问题差不多。我正在寻找一种比在集合中进行全面搜索更有效的算法。

我有两个集合:

List<Map<TypeId, Object> > col1;
List<Entity> col2;

在哪里

public enum TypeId{
    PLAYER,
    PARTNER,
    PLATFORM,
    AMOUNT
}

public class Entity{
    private int player_id;
    private int platform_id
    private BigDecimal amount;

    //GET, SET
}

col1 List<Map<TypeId, Object> > 类型的集合仅包含 PLAYER, PARTNER, PLATFORM TypeId秒。

我需要写一个方法:

public List<Map<TypeId, Object> > merge(List<Map<TypeId, Object> > col1, List<Entity> col2){
    //Impl
}

它将产生 List<Map<TypeId, Object> >每个条目 entry map 的 包含额外的键值 (AMOUNT, AMOUNT's value)其中 AMOUNT's valueamount 的值实例字段 eEntity如果e.player_id = entry.get(PLAYER) && e.platform_id = entry.get(PLATFORM)null否则。

其实操作和

是一样的
col1 LEFT OUTER JOIN 
col2 ON e.player_id = entry.get(PLAYER) && e.platform_id = entry.get(PLATFORM)

示例:

col1:
[{PLATFORM: 1, PARTNER: 1, PLAYER: 1},
 {PLATFORM: 1, PARTNER: 3, PLAYER: 1},
 {PLATFORM: 2, PARTNER: 1, PLAYER: 2}
 {PLATFORM: 3, PARTNER: 4, PLAYER: 5}]

col2:
[Entity(platform_id = 1, player_id = 1, amount = 100),
Entity(platform_id = 2, player_id = 2, amount = 200),
Entity(platform_id = 3, player_id = 4, amount = 300)]

result:
[{PLATFORM: 1, PARTNER: 1, PLAYER: 1, AMOUNT: 100},
 {PLATFORM: 1, PARTNER: 3, PLAYER: 1, AMOUNT: 100},
 {PLATFORM: 2, PARTNER: 1, PLAYER: 2, AMOUNT: 200},
 {PLATFORM: 3, PARTNER: 4, PLAYER: 5, AMOUNT: null}]

最佳答案

更容易就地进行更改,修改 col1 列表而不是创建新的 List。这是 Java-8 解决方案:

public List<Map<TypeId, Object> > merge(List<Map<TypeId, Object> > col1, List<Entity> col2){
    col1.forEach(map -> map.put(TypeId.AMOUNT, 
        col2.stream()
            .filter(e -> e.player_id == (int)map.get(TypeId.PLAYER) && 
                         e.platform_id == (int)map.get(TypeId.PLATFORM))
            .findFirst().map(e -> e.amount).orElse(null)
        ));
    return col1;
}

我想在这种情况下,就地更改 col1 是令人满意的。请注意,即使您将结果存储到新列表中,如果您修改现有 map ,它也将无用。因此,要使结果完全独立于 col1,您必须复制所有 map 。

另请注意,它不是很有效,因为它遍历 col2 的每个 col1 条目,因此复杂度大致为 col1.size()*col2。大小()。在您的情况下,最好丢弃 Entity 类并创建一个仅存储 platformId 和 playerId 的新类(正确实现 equalshashCode) 并将其用作映射键:

public static class PlatformAndPlayer {
    private final int playerId, platformId;

    public PlatformAndPlayer(int playerId, int platformId) {
        this.playerId = playerId;
        this.platformId = platformId;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + platformId;
        result = prime * result + playerId;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PlatformAndPlayer other = (PlatformAndPlayer) obj;
        if (platformId != other.platformId)
            return false;
        if (playerId != other.playerId)
            return false;
        return true;
    }
}

这样您将拥有一个 Map 而不是 col2 列表:

Map<PlatformAndPlayer, BigDecimal> col2 = new HashMap<>();
col2.put(new PlatformAndPlayer(1, 1), BigDecimal.valueOf(100));
col2.put(new PlatformAndPlayer(2, 2), BigDecimal.valueOf(200));
col2.put(new PlatformAndPlayer(3, 4), BigDecimal.valueOf(300));

现在您的任务可以轻松有效地解决(即使使用 Java 5):

public static List<Map<TypeId, Object>> merge(
        List<Map<TypeId, Object>> col1,
        Map<PlatformAndPlayer, BigDecimal> col2) {
    for (Map<TypeId, Object> map : col1) {
        map.put(TypeId.AMOUNT, col2.get(new PlatformAndPlayer(
            (int) map.get(TypeId.PLAYER), (int) map.get(TypeId.PLATFORM))));
    }
    return col1;
}

关于java - 两个集合的左外连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30612900/

相关文章:

c# - 如何在 C# 中有效地从另一个列表中减去一个巨大的列表

java - 在 Java 集合排序中使用 Comparator 接口(interface)比较方法返回值 -1, 0, 1 到底意味着什么?

java - 为什么应该首选 Java 类的接口(interface)?

java - SWT JFace : How to make TableViewer always selects a row?

java - 如何将对象从表格单元格编辑器传递到表模型?

java - Java 中的函数 "composition"和类型安全

java - 尝试多线程 URL 连接以减少加载时间

javascript - 无法使用 CoffeeScript 在 Meteor 中创建仅限客户端的集合

java - HashMap 有支持数组,那为什么它是无序的

Java 中断与返回