问题几乎在标题中。我正在寻找一种比通过集合完全搜索更有效的算法。
我有两个系列:
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
,其中包含其他键值(AMOUNT, AMOUNT's value)
,其中AMOUNT's value
是amount
的值e
的{{1}}实例的字段,如果Entity
,则e.player_id = entry.get(PLAYER) && e.platform_id = entry.get(PLATFORM)
。{/ p>
实际上,操作与
相同null
示例:
col1 LEFT OUTER JOIN
col2 ON e.player_id = entry.get(PLAYER) && e.platform_id = entry.get(PLATFORM)
答案 0 :(得分:1)
更容易进行就地更改,修改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
到位是令人满意的。请注意,即使将结果存储到新列表中,如果修改现有映射也无效。因此,要使结果完全独立于col1
,您必须复制所有地图。
另请注意,对于遍历col1
的每个col2
条目,它不是很有效,因此复杂度大致为col1.size()*col2.size()
。在你的情况下,最好扔掉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;
}
}
通过这种方式代替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));
现在您的任务可以轻松有效地解决(即使使用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;
}
答案 1 :(得分:1)
Guava库提供了适合这些转换的功能习惯用法。以下是使用Guava的方法的示例实现,不需要更改方法签名:
public List<Map<TypeId, Object>> merge(List<Map<TypeId, Object>> col1,
List<Entity> col2) {
// create a lookup table for getting the amounts
// based on entities (entity keys)
final Map<Entity, BigDecimal> entityLookupTable = Maps.toMap(col2,
new Function<Entity, BigDecimal>() {
@Override
public BigDecimal apply(Entity entity) {
return entity.getAmount();
}
});
// transform the col1 list using a transform function
// that adds the AMOUNT fetched from the lookup table to each entry map
return Lists.transform(col1, new Function<Map<TypeId, Object>,
Map<TypeId, Object>>() {
@Override
public Map<TypeId, Object> apply(Map<TypeId, Object> typeToValueMap) {
Entity keyWrapper = new Entity(
new EntityKey(
(Integer) typeToValueMap.get(TypeId.PLAYER),
(Integer) typeToValueMap.get(TypeId.PLATFORM)),
null);
typeToValueMap.put(TypeId.AMOUNT,
entityLookupTable.get(keyWrapper));
return typeToValueMap;
}
});
}
但是,需要创建一个标识实体的EntityKey
类(类似于DB中的主键)。然后,可以使用此类在equals
中实现hashCode
(和Entity
),从而在查找映射中存储实体。
public class EntityKey {
private int player_id;
private int platform_id;
public EntityKey(int player_id, int platform_id) {
this.player_id = player_id;
this.platform_id = platform_id;
}
/* Generated by Eclipse */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + platform_id;
result = prime * result + player_id;
return result;
}
/* Generated by Eclipse */
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EntityKey other = (EntityKey) obj;
if (platform_id != other.platform_id)
return false;
if (player_id != other.player_id)
return false;
return true;
}
}
public class Entity {
private EntityKey key;
private BigDecimal amount;
public Entity(EntityKey key, BigDecimal amount) {
this.key = key;
this.amount = amount;
}
/* Generated by Eclipse */
/* Simply delegates to EntityKey */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
/* Generated by Eclipse */
/* Simply delegates to EntityKey */
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entity other = (Entity) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
/**
* @return the amount
*/
public BigDecimal getAmount() {
return amount;
}
}