remove object from array if property value match - javascript

I have array of objects that look like:
{
"brandid": id,
"brand": string,
"id": id,
"categoryId": id,
"category": string,
"factory": string,
"series": string,
"status": 0,
"subStatus": 1
}
if the series property value matches another series property value in the other objects in the array, that object needs to be removed from the array.
Currently I have attempted to push them to a duplicate Array with :
const seriesResCopy = seriesRes;
const dupArray = []
for (const thing of seriesResCopy) {
for (const item of seriesRes) {
if (thing.series === item.series) {
dupArray.push(item);
}
}
}
but this does not work. From examples I have seem my issue has been that I do not have a definite list of duplicate values to look for.
Any help would be much appreciated.

You could use a Set of series to filter out duplicates:
const exists = new Set();
seriesRes = seriesRes.filter(({series}) => !exists.has(series) && exists.add(series));
This uses: Array.prototype.filter, Object destructuring and some logical tricks.
The same can be done by mutating the array:
const exists = new Set();
for(const [index, {series}] of seriesRes.entries()) {
if(!exists.has(series) {
exists.add(series);
} else {
seriesRes.splice(index, 1);
}
}

To filter duplicates from the array and keep the first instance:
let seriesWithoutDuplicates = seriesRes.filter((s, i, self) => {
return self.findIndex(z => z.series === s.series) === i;
});

Related

Create new object with unique elements from objects of array of objects

I have an Array of Objects. Every object in this Array has some Keypairs. One of this Keypairs ("obj", for example) is an Array of Objects too.
Example what I have:
const arrOfObj = [
{
"id": 1
"obj": {
"arr1": ["arr1-1"],
"arr2": ["arr2-1", "arr2-2"],
"arr3": ["arr3-1", "arr3-2"]
}
},
{
"id": 1
"obj": {
"arr1": ["arr1-2"],
"arr2": ["arr2-1", "arr2-3"],
"arr3": ["arr3-1", "arr3-3"],
"arr4": ["arr4-1"],
}
},
];
I need to get new Object of "obj" Objects with unique keys and unique elements inside them.
Example what I need:
const newObj = {
"arr1": ["arr1-1", "arr1-2"],
"arr2": ["arr2-1", "arr2-2", "arr2-3"],
"arr3": ["arr3-1", "arr3-2", "arr3-3"],
"arr4": ["arr4-1"],
}
All of this comes dynamically from API by request, so I don`t know the names of this keypairs, but i need to store them.
I have Solution, but I`m new in JavaScript, and want to know how to simplify and improve my poor Code.
1. First, I`m defining the new Object and retrieving the Names for his keypairs from "arrOfObj".
let filterObj = {};
arrOfObj.forEach(function (item) {
for (let key in item.obj) {
filterObj[key] = [];
}
});
2. After that I`m getting all the Elements of every Array from "arrOfObj" and store them in new Object "filterObj" in the Keypair with the same Name.
arrOfObj.forEach(function (item) {
for (let key in item.obj) {
for (let element = 0; element < item.obj[key].length; element++) {
filterObj[key].push(item.obj[key][element]);
}
}
});
3. To the end I`m filtering Arrays to get unique Elements only.
for (let key in filterObj) {
filterObj[key] = Array.from(new Set(filterObj[key]));
}
It works, I`ve got what I want, but it seems to much monstrously. How this code can be simplified the best way?
Thanks for the help and advices.
You can use some destructuring and Object.entries() and Object.keys() to streamline this and do everything to the new Object only
const newObj = {}
arrOfObj.forEach(({obj}) => {
Object.entries(obj).forEach(([k, arr]) => {
newObj[k] = newObj[k] || [];
newObj[k].push(...arr);
})
});
Object.keys(newObj).forEach(k => newObj[k] = [...new Set(newObj[k])]);
console.log(newObj)
<script>
const arrOfObj=[{id:1,obj:{arr1:["arr1-1"],arr2:["arr2-1","arr2-2"],arr3:["arr3-1","arr3-2"]}},{id:1,obj:{arr1:["arr1-2"],arr2:["arr2-1","arr2-3"],arr3:["arr3-1","arr3-3"],arr4:["arr4-1"]}}];
</script>
Another solution using Object#fromEntries, Array#reduce, Object#entries, Array#forEach, Set, and Map:
const arrOfObj = [ { "id": 1, "obj": { "arr1": ["arr1-1"], "arr2": ["arr2-1", "arr2-2"], "arr3": ["arr3-1", "arr3-2"] } }, { "id": 1, "obj": { "arr1": ["arr1-2"], "arr2": ["arr2-1", "arr2-3"], "arr3": ["arr3-1", "arr3-3"], "arr4": ["arr4-1"] } } ];
const filterObj =
// transform the resulting list of key-values pairs to an object at the end
Object.fromEntries(
// get a map of array name as key and its unique items as value
[...arrOfObj.reduce((map, { obj = {} }) => {
// iterate over current element's object to update the map
Object.entries(obj).forEach(([currentKey, currentValues]) => {
const keyValues = [...(map.get(currentKey) || []), ...currentValues];
map.set(currentKey, [...new Set(keyValues)]);
});
return map;
}, new Map)]
);
console.log(filterObj);

Javascript - how to loop through dict inside a list

So I am pretty new when it comes to Javascript and it is as simple as read a json list with a value of:
{
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
What I would like to do is to have both the URL and the amount of numbers etc
"https://testing.com/en/p/-12332423/" and "999"
and I would like to for loop so it runs each "site" one by one so the first loop should be
"https://testing.com/en/p/-12332423/" and "999"
second loop should be:
"https://testing.com/en/p/-123456/" and "123"
and so on depending on whats inside the json basically.
So my question is how am I able to loop it so I can use those values for each loop?
As Adam Orlov pointed out in the coment, Object.entries() can be very useful here.
const URLobj = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
};
URLobj.URL.forEach(ob => {
console.log('ob', ob);
const entries = Object.entries(ob)[0]; // 0 just means the first key-value pair, but because each object has only one we can just use the first one
const url = entries[0];
const number = entries[1];
console.log('url', url);
console.log('number', number);
})
You mean something like this using Object.entries
const data = {
"URL": [
{"https://testing.com/en/p/-12332423/": "999"},
{"https://testing.com/en/p/-123456/": "123"},
{"https://testing.com/en/p/-456436346/": "422"}
]
}
data.URL.forEach(obj => { // loop
const [url, num] = Object.entries(obj)[0]; // grab the key and value from each entry - note the [0]
console.log("Url",url,"Number", num); // do something with them
})
let's call your object o1 for simplicity. So you can really go to town with this link - https://zellwk.com/blog/looping-through-js-objects/
or you can just use this code :
for(var i = 0; i < o1.URL.length; i++) {
//each entry
var site = Object.keys(URL[i]) [0];
var value = Object.values(URL[i]) [0];
// ... do whatever
}
don't forget each member of the array is an object (key : value) in its own right
You can extract the keys and their values into another object array using map
Then use the for loop on the newly created array. You can use this method on any object to separate their keys and values into another object array.
const data = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
var extracted = data.URL.map(e => ({
url: Object.keys(e)[0],
number: Object.values(e)[0]
}))
extracted.forEach((e) => console.log(e))

Creating a JavaScript function that filters out duplicate in-memory objects?

Okay, so I am trying to create a function that allows you to input an array of Objects and it will return an array that removed any duplicate objects that reference the same object in memory. There can be objects with the same properties, but they must be different in-memory objects. I know that objects are stored by reference in JS and this is what I have so far:
const unique = array => {
let set = new Set();
return array.map((v, index) => {
if(set.has(v.id)) {
return false
} else {
set.add(v.id);
return index;
}
}).filter(e=>e).map(e=>array[e]);
}
Any advice is appreciated, I am trying to make this with a very efficient Big-O. Cheers!
EDIT: So many awesome responses. Right now when I run the script with arbitrary object properties (similar to the answers) and I get an empty array. I am still trying to wrap my head around filtering everything out but on for objects that are referenced in memory. I am not positive how JS handles objects with the same exact key/values. Thanks again!
Simple Set will do the trick
let a = {'a':1}
let b = {'a': 1,'b': 2, }
let c = {'a':1}
let arr = [a,b,c,a,a,b,b,c];
function filterSameMemoryObject(input){
return new Set([...input])
}
console.log(...filterSameMemoryObject(arr))
I don't think you need so much of code as you're just comparing memory references you can use === --> equality and sameness .
let a = {'a':1}
console.log(a === a ) // return true for same reference
console.log( {} === {}) // return false for not same reference
I don't see a good reason to do this map-filter-map combination. You can use only filter right away:
const unique = array => {
const set = new Set();
return array.filter(v => {
if (set.has(v.id)) {
return false
} else {
set.add(v.id);
return true;
}
});
};
Also if your array contains the objects that you want to compare by reference, not by their .id, you don't even need to the filtering yourself. You could just write:
const unique = array => Array.from(new Set(array));
The idea of using a Set is nice, but a Map will work even better as then you can do it all in the constructor callback:
const unique = array => [...new Map(array.map(v => [v.id, v])).values()]
// Demo:
var data = [
{ id: 1, name: "obj1" },
{ id: 3, name: "obj3" },
{ id: 1, name: "obj1" }, // dupe
{ id: 2, name: "obj2" },
{ id: 3, name: "obj3" }, // another dupe
];
console.log(unique(data));
Addendum
You speak of items that reference the same object in memory. Such a thing does not happen when your array is initialised as a plain literal, but if you assign the same object to several array entries, then you get duplicate references, like so:
const obj = { id: 1, name: "" };
const data = [obj, obj];
This is not the same thing as:
const data = [{ id: 1, name: "" }, { id: 1, name: "" }];
In the second version you have two different references in your array.
I have assumed that you want to "catch" such duplicates as well. If you only consider duplicate what is presented in the first version (shared references), then this was asked before.

How to not display duplicates from many objects in an Array

How can I make sure that no duplicates are displayed with vue inside a template ?
I my case the data is an array of objects and key that has a value of an object with multiple objects within it. So this would be a nested v-for in vue template syntax.
{
"matches": [
{
"birthday": "1/29/2019",
"household": {
"0": {
"relationship": "brother"
},
"1": {
"relationship": "brother"
}
}
}
]
}
I would only like to display 1 unique relationship per household. Please see fiddle for further examination https://jsfiddle.net/sxmhv3t7/
You can use computed property to make matches array unique.
For example:
computed: {
uniqueMatches () {
return this.matches.map(item => {
let households = Object.values(item.household)
let relationships = households.map(item => item.relationship)
const uniqueRelationships = [...new Set(relationships)]
item.household = uniqueRelationships.reduce((acc, cur, idx) => {
acc[idx] = {}
acc[idx].relationship = cur
return acc
}, {})
console.log(item)
return item
})
}
}
and then use uniqueMatches instead of matches in template
Demo in jsfiddle
You could massage the data a bit and create a uniqueHouseholdMembers array property on each match in the matches array and then just print out those values:
matches.forEach(match => {
let houseHolds = Object.values(match.household);
match.uniqueHouseholdMembers = houseHolds.reduce((acc, household) => {
// check if household member has already been added to our growing list
let isUniqueRelationship = !acc.includes(household.relationship);
// add household member if unique
if (isUniqueRelationship) {
acc.push(household.relationship);
}
return acc;
}, []);
});
// output using the data you provided:
// match[0].uniqueHouseholdMembers -> ['brother']
// match[1].uniqueHouseholdMembers -> ['sister']
// and if you have a 3rd match entry with more household members:
// match[2].uniqueHouseholdMembers -> ['brother', 'father', 'stranger']

JavaScript loop through array, remove duplicates per one value, then push to new array with that value and one other

I have an array of objects coming to my Vuejs front-end via api call and I am attempting to loop through, remove duplicates, then return a new array with unique "phases" and their associated "id's". The original array has several other key/values I do not need. I am also sorting them in order by the phase number. Here's my code:
salesPhases () {
let phases = this.$store.state.addresses.salesPhases
let uniquePhases = []
for (let i = 0; i < phases.length; i++) {
if (uniquePhases.indexOf(phases[i].phase_number) === -1) {
uniquePhases.push(phases[i].phase_number)
}
}
return uniquePhases.sort((a, b) => {
return a - b
})
}
The above code works for everything I need, minus including the id. Here's my attempt at doing that, which then negates the unique phases condition.
uniquePhases.push([phases[i].phase_number, phases[i].id])
The sort still works, but it is then sorting one big single-dimensional array. The array of phases looks something like this:
{ "data": [
{
"id": "94e224af-135f-af31-3619-535acfae9930",
"street_address1": "407 48TH ST E",
"street_address2": null,
"phase": "101",
"sales_rep": "164",
"id": "abd90d6b-28a8-2be6-d6c1-abd9007aef38",
"name": "48TH ST E",
"block_minimum": 400,
"block_maximum": 498,
"side": 2
},
{
"id": "94e224af-135f-af31-3619-535acfae9930",
"street_address1": "407 48TH ST E",
"street_address2": null,
"phase": "101",
"sales_rep": "164",
"id": "abd90d6b-28a8-2be6-d6c1-abd9007aef38",
"name": "48TH ST E",
"block_minimum": 401,
"block_maximum": 499,
"side": 1
}
]
You can filter the array to get only unique, using a Set, then map the items into new objects that contain only the id and the phase_number, and then sort by the phase_number:
salesPhases () {
const uSet = new Set()
return this.$store.state.addresses.salesPhases
.filter(({ phase_number }) => uSet.has(phase_number) ? false : uSet.add(phase_number)) // get uniques by phase_number
.map(({ id, phase_number }) => ({ id, phase_number })) // get an object with the id and the phase_number
.sort((a, b) => a.phase_number - b.phase_number) // sort by phase_number
}
You can also use reduce and Map, and then spread the Map.values() iterator to an array
salesPhases () {
return [...this.$store.state.addresses.salesPhases
.reduce((m, { id, phase_number }) =>
m.has(phase_number) ? m : m.set(phase_number, { id, phase_number }), new Map()) // set to map, if phase_number key doesn't exist
.values()] // convert the Map values to an array
.sort((a, b) => a.phase_number - b.phase_number) // sort by phase_number
}
One solution is to update your code to push the entire phase object, rather than just the phase number, and then use the Array find method instead of indexOf, to check if a phase with the given number is found.
Try this:
salesPhases () {
let phases = this.$store.state.addresses.salesPhases
let uniquePhases = []
for (let i = 0; i < phases.length; i++) {
if (!uniquePhases.find(x => x.phase_number === phases[i].phase_number)) {
uniquePhases.push(phases[i])
}
}
return uniquePhases.sort((a, b) => {
return a.phase_number - b.phase_number
})
}
I would leverage lodash for this: https://lodash.com/docs#sortedUniqBy
salesPhases () {
return _.sortedUniqBy(this.$store.state.addresses.salesPhases,
phase => phase.phase_number)
}

Categories