Reputation: 619
I've two arrays which contain the same kind of objects (same attributes but different values associated). I want to compare the two arrays and match the objects that are equal except for one property. Then I want to find the index of the objects-matched in the first array in order to push those objects into a different array.
I think that all of this can be made using lodash and I would like to avoid for loops, in order to make it the more efficient as possible
Note that I am working in a js class
Here's my attempt (not working)
class MatchPlayers {
constructor(){
this.TeamA = [
{weight:'75',height:'170', foot:'Left', available:true},
{weight:'88',height:'190', foot:'Right', available:true},
{weight:'65',height:'163', foot:'Right', available:false},
{weight:'70',height:'168', foot:'Left', available:true}
]
this.TeamB = [
{weight:'75',height:'170', foot:'', available:true},
{weight:'93',height:'201', foot:'', available:true},
{weight:'65',height:'163', foot:'', available:false}
]
this.MatchedPlayers = []
}
PlayersMatch (){
for(this.i=0;this.i<this.TeamA.length;this.i++){
if (_.intersection(this.TeamA,{weight:this.TeamB.weight, height:this.TeamB.height, available:this.TeamB.available})){
this.position = _.findIndex(this.TeamA,{weight:this.TeamB.weight, height:this.TeamB.height, available:this.TeamB.available})
this.MatchedPlayers.push(this.TeamA[this.position])
} else {console.log('No matchable players')}
}
console.log(this.MatchedPlayers)
}
}
In this case I want to match the objects which have the same attributes except for "foot", so the expected output would be:
//Expected Output:
this.MatchedPlayers = [
{weight:'75',height:'170', foot:'Left', available:true},
{weight:'65',height:'163', foot:'Right', available:false}
]
Upvotes: 3
Views: 744
Reputation: 192607
To create an intersection with a custom behaviour, use _.intersectionWith()
. The method accepts a predicate that compares between two objects. In this case the comparison is almost identical to _.isEqual()
, but it should ignore a property.
You can create the predicate with _.isEqualWith()
, which accepts a customizer function. If the compared key (the 3rd param) is foot
it should return true
(equal because we don't care), if not it should return undefined
so that _.isEqualWith()
can make the standard _.isEqual()
comparisons.
const a = [{ weight: '75', height: '170', foot: 'Left', available: true }, { weight: '88', height: '190', foot: 'Right', available: true }, { weight: '65', height: '163', foot: 'Right', available: false }, { weight: '70', height: '168', foot: 'Left', available: true }];
const b = [{ weight: '75', height: '170', foot: '', available: true }, { weight: '93', height: '201', foot: '', available: true }, { weight: '65', height: '163', foot: '', available: false }];
const result = _.intersectionWith(a, b,
_.partialRight(_.isEqualWith,
(...args) => args[2] === 'foot' ? true : undefined
)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Upvotes: 0
Reputation: 386756
You could take a simplified approach and omit foot
property and get the intersection by _.isEqual
for the lefot over properties.
var a = [{ weight: '75', height: '170', foot: 'Left', available: true }, { weight: '88', height: '190', foot: 'Right', available: true }, { weight: '65', height: '163', foot: 'Right', available: false }, { weight: '70', height: '168', foot: 'Left', available: true }],
b = [{ weight: '75', height: '170', foot: '', available: true }, { weight: '93', height: '201', foot: '', available: true }, { weight: '65', height: '163', foot: '', available: false }],
omitFoot = o => _.omit(o, 'foot'),
intersection = _.intersectionWith(
_.map(a, omitFoot),
_.map(b, omitFoot),
_.isEqual
);
console.log(intersection);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Upvotes: 2