标题中的问题差不多。我正在寻找一种比在集合中进行全面搜索更有效的算法。
我有两个集合:
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 value
是 amount
的值实例字段 e
的 Entity
如果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 的新类(正确实现 equals
和 hashCode
) 并将其用作映射键:
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/