java - LEFT OUTER JOIN of two collections -


the question pretty in title. i'm looking algorithm more efficient full search through collections.

i have 2 collections:

list<map<typeid, object> > col1; list<entity> col2; 

where

public enum typeid{     player,     partner,     platform,     amount } 

and

public class entity{     private int player_id;     private int platform_id     private bigdecimal amount;      //get, set } 

the col1 collection of type list<map<typeid, object> > contains player, partner, platform typeids.

i need write method:

public list<map<typeid, object> > merge(list<map<typeid, object> > col1, list<entity> col2){     //impl } 

which going produce list<map<typeid, object> > each entry entry of map contains additional key-value (amount, amount's value) amount's value value of amount field of instance e of entity if e.player_id = entry.get(player) && e.platform_id = entry.get(platform) , null otherwise.

in fact, operation same as

col1 left outer join  col2 on e.player_id = entry.get(player) && e.platform_id = entry.get(platform) 

sample:

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}] 

it's easier make changes in-place, modifying col1 list instead of creating new list. here's java-8 solution:

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; } 

i suppose changing col1 in place satisfactory in case. note if store result new list, useless if modify existing maps. make result totally independent col1, have copy maps.

also note it's not effective each col1 entry traverses col2, complexity col1.size()*col2.size(). it's better in case throw away entity class , create new 1 stores platformid , playerid (with implemented equals , hashcode) , use map key:

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;     } } 

this way instead of col2 list have 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)); 

now task can solved , (even java 5):

public static list<map<typeid, object>> merge(         list<map<typeid, object>> col1,         map<platformandplayer, bigdecimal> col2) {     (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; } 

Comments