Reputation: 20289
I have an array of room objects and I am currently removing duplicates objects from the array based on their room_rate_type_id
property:
const rooms = [{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
const newRooms = rooms.filter((room, index, array) => {
const roomRateTypeIds = rooms.map(room => room.room_rate_type_id);
// Returns the first index found.
return roomRateTypeIds.indexOf(room.room_rate_type_id) === index;
});
console.log(newRooms);
However I also need to make sure that objects only get removed if not only their room_rate_type_id
matches but also their price.
I can understand how the filter functionality works in my given example but I am unsure how to cleanly do a check for the price as well, preferably in ES6.
Upvotes: 6
Views: 5147
Reputation: 2384
const rooms = [
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
let newRooms = rooms.filter((x, i, arr) => arr.findIndex(y => y.room_rate_type_id === x.room_rate_type_id && y.price === x.price) === i);
console.log(newRooms);
Upvotes: 0
Reputation: 191916
You can reduce the array to a Map object by creating a key from both properties, and adding the object to the Map only if the key doesn't already exist. Then spread the Map#values back to an array:
const rooms = [{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
const newRooms = [...rooms.reduce((m, r) => {
const key = `${r.room_rate_type_id}-${r.price}`; // create the key by combining both props
return m.has(key) ? m : m.set(key, r); // if key exists skip, if not add to map
}, new Map()).values()]; // get the map values and convert back to array
console.log(newRooms);
Upvotes: 4
Reputation: 6862
This would do it:
const rooms = [{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
const newRooms = rooms.reduce((rooms, room) => {
let l = rooms.filter(r => {
return r.room_rate_type_id === room.room_rate_type_id && r.price === room.price;
});
if (l.length === 0) {
return [...rooms, room]
}
return rooms;
}, [rooms[0]]);
console.log(newRooms);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 92854
Simple approach: using concatenation of room_rate_type_id
and price
keys as unique key:
const rooms = [
{room_rate_type_id: 202,price: 200},{room_rate_type_id: 202,price: 200},{room_rate_type_id: 202,price: 189},{room_rate_type_id: 190,price: 200}
];
const roomRateKeys = [];
const newRooms = rooms.filter((r, i, a) => {
var k = r.room_rate_type_id + "" + r.price;
if (roomRateKeys.indexOf(k) === -1) {
roomRateKeys.push(k);
return r;
}
});
console.log(newRooms);
Upvotes: 1
Reputation: 1073968
For a smallish array, you can do it by repeating looking for other matching rooms:
const newRooms = rooms.filter((room, index) => {
// Only include this room if there isn't another room earlier
// in the array that has the same values
return !rooms.some((r, i) =>
i < index &&
r.room_rate_type_id == room.room_rate_type_id &&
r.price == room.price
);
});
const rooms = [{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
const newRooms = rooms.filter((room, index) => {
// Only include this room if there isn't another room earlier
// in the array that has the same values
return !rooms.some((r, i) =>
i < index &&
r.room_rate_type_id == room.room_rate_type_id &&
r.price == room.price
);
});
console.log(newRooms);
.as-console-wrapper {
max-height: 100% !important;
}
If the array is really large, that gets inefficient and you may be better off remembering combinations you've seen before rather than constantly re-searching the array:
const seenRooms = Object.create(null);
const newRooms = rooms.filter((room, index) => {
const key = room.room_rate_type_id + "**" + room.price;
if (seenRooms[key]) {
return false;
}
seenRooms[key] = true;
return true;
});
const rooms = [{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
const seenRooms = Object.create(null);
const newRooms = rooms.filter((room, index) => {
const key = room.room_rate_type_id + "**" + room.price;
if (seenRooms[key]) {
return false;
}
seenRooms[key] = true;
return true;
});
console.log(newRooms);
.as-console-wrapper {
max-height: 100% !important;
}
Those are written for clarity; you can make them more concise if you like.
Upvotes: 2
Reputation: 10458
You can do
const rooms = [
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 200
},
{
room_rate_type_id: 202,
price: 189
},
{
room_rate_type_id: 190,
price: 200
}
];
let result = rooms.filter((e, i) => {
return rooms.findIndex((x) => {
return x.room_rate_type_id == e.room_rate_type_id && x.price == e.price;}) == i;
});
console.log(result);
This would filter all duplicates except the first occurrence of any object
Upvotes: 14