问题几乎在标题中.我正在寻找比通过集合完全搜索更有效的算法.
我有两个集合:
List<Map<TypeId, Object> > col1;
List<Entity> col2;
Run Code Online (Sandbox Code Playgroud)
哪里
public enum TypeId{
PLAYER,
PARTNER,
PLATFORM,
AMOUNT
}
Run Code Online (Sandbox Code Playgroud)
和
public class Entity{
private int player_id;
private int platform_id
private BigDecimal amount;
//GET, SET
}
Run Code Online (Sandbox Code Playgroud)
该col1类型的集合List<Map<TypeId, Object> >仅包含PLAYER, PARTNER, PLATFORM TypeIds.
我需要写一个方法:
public List<Map<TypeId, Object> > merge(List<Map<TypeId, Object> > col1, List<Entity> col2){
//Impl
}
Run Code Online (Sandbox Code Playgroud)
这是会产生List<Map<TypeId, Object> >各个入口entry地图包含其他键值(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)
Run Code Online (Sandbox Code Playgroud)
样品:
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}]
Run Code Online (Sandbox Code Playgroud)
就地更改更容易,修改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;
}
Run Code Online (Sandbox Code Playgroud)
我认为col1在这种情况下改变就地是令人满意的。请注意,即使将结果存储到新列表中,如果修改现有地图也将毫无用处。因此,为了使结果完全独立于col1,您必须复制所有地图。
col1另请注意,对于它遍历的每个条目来说,它并不是非常有效col2,因此复杂度大约为col1.size()*col2.size()。在您的情况下,最好丢弃一个Entity类并创建一个仅存储 platformId 和 playerId 的新类(正确实现equalsand 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;
}
}
Run Code Online (Sandbox Code Playgroud)
这样col2您将得到一个而不是列表Map:
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));
Run Code Online (Sandbox Code Playgroud)
现在您的任务可以轻松有效地解决(即使使用 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;
}
Run Code Online (Sandbox Code Playgroud)