I am trying to push objects into my array. The problem is some objects are duplicated.
My codes are as following:
var obj = {
'obj1 {
'id':'1', 'title':'title 1'
},
'obj2 {
'id':'2', 'title':'title 2'
},
'obj3 {
'id':'3', 'title':'title 3'
}, //duplicated
'obj3 {
'id':'3', 'title':'title 3'
},
'obj4 {
'id':'4', 'title':'title 4'
}
// and many more..
}
var arr= [];
for (i in obj){
arr.push(obj[i])
}
I am not sure how to find out the duplicated obj and only push the unique objects into my arr.
Can someone help me out? Thanks a lot!
If your objects are stored in an array (it's hard to tell via your example) you could use the following function to get unique objects from that array based on one or more properties of the objects stored:
// get unique object members by property name(s)
function unique(arr, props) {
var results = [],
seen = [];
for (var i=0; i < arr.length; i++){
var key = "";
for (var j=0; j < props.length; j++) {
key += "" + arr[i][props[j]];
}
if (seen.indexOf(key) == -1) {
seen.push(key);
results.push(arr[i]);
}
}
return results;
}
var obj = [
{ 'id': 1, 'title': 'title 1' },
{ 'id': 2, 'title': 'title 2' },
{ 'id': 3, 'title': 'title 3' },
{ 'id': 3, 'title': 'title 3' },
{ 'id': 4, 'title': 'title 4' }
];
var results = unique(obj, [ 'id', 'title' ]);
// results => [ obj[0], obj[1], obj[2], obj[4] ]
You can dedupe this way if performance isn't an issue.
var deduped = {};
for (var i in obj) {
deduped[JSON.stringify(obj[i])] = obj[i];
}
Related
I have a problem with a for loop. What the problem is I have a for that is going through an object and it is only going through the array once. How can I loop through the entire object array loop? The current code is below:
var i = 0;
for (var key in data) {
console.log(data[key].allProducts[i]);
i++;
}
Well, since you are use the indexes here, why not at once use a for...of loop instead? Then you don't have any need accessing the properties itself
Depending on your data object, you might need to use Object.values( data ) or stick with your previous for...in loop, but I guess the principle is clear :)
const data = {
group1: {
allProducts: [
{ id: 1, name: 'product 1' },
{ id: 2, name: 'product 2' },
{ id: 3, name: 'product 3' },
{ id: 4, name: 'product 4' }
]
},
group2: {
allProducts: [
{ id: 5, name: 'product 5' }
]
}
};
for (let item of Object.values( data) ) {
for (let product of item.allProducts) {
console.log(product);
}
}
You only have one loop trying to control two variables, which isn't what you're trying to do. Assuming data keys are something like ['a', 'b', 'c'], you're actually getting data['a'][1], data['b'][2], data['c'][3].
What you need is two nested loops:
for (var key in data) {
var productsLength = data[key].allProducts.length;
for (var i = 0; i < productsLength; i++) {
console.log(data[key].allProducts[i]);
}
}
This is my array object
var item = [
{index:1, name: 'miraje'},
{index:2, name: 'alamin'},
{index:3, name: 'behestee'},
{index:4, name: 'arif'},
{index:5, name: 'riad'}
];
when i delete an object like index: 2 , and that time i want to update my index value like ..
var item = [
{ index: 1, name: 'miraje'},
{ index: 2, name: 'behestee'},
{ index: 3, name: 'arif'},
{ index: 4, name: 'riad'}
];
After you remove element you can use forEach() loop to change indexes.
var item = [
{index:1, name: 'miraje'},
{index:2, name: 'alamin'},
{index:3, name: 'behestee'},
{index:4, name: 'arif'},
{index:5, name: 'riad'}
];
item.splice(1, 1)
item.forEach((e, i) => e.index = i + 1)
console.log(item)
Remove the object and alter the index property of each object,
DEMO
i=1;
var item = [
{index:1, name: 'miraje'},
{index:2, name: 'alamin'},
{index:3, name: 'behestee'},
{index:4, name: 'arif'},
{index:5, name: 'riad'}
];
console.log(item);
delete item[ 2 ];
console.log(item);
item.forEach(function(obj) {
obj.index = i;
debugger;
i++;
});
console.log(item);
Basically, you need to find the item with index, delete it, and to update all following items.
function deleteItem(array, index) {
var i = 0, found = false;
while (i < array.length) {
if (found) {
--array[i].index;
++i;
continue;
}
if (found = array[i].index === index) {
array.splice(i, 1);
continue;
}
++i;
}
}
var items = [{ index: 1, name: 'miraje' }, { index: 2, name: 'alamin' }, { index: 3, name: 'behestee' }, { index: 4, name: 'arif' }, { index: 5, name: 'riad' }];
deleteItem(items, 2);
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Just for a variety, without modifying the original array an efficient O(n) approach would also be as follows. We can also provide a range to delete the elements as well...
The range is provided supplied with the array indices, not the object index properties.
var item = [
{index:1, name: 'miraje'},
{index:2, name: 'alamin'},
{index:3, name: 'behestee'},
{index:4, name: 'arif'},
{index:5, name: 'riad'}
];
function deleteObjectsFromArray(a,j,k){
return a.reduceRight((p,c,i) => i >= j && i < k ? p
: i >= k ? (c.index -= k-j, p[c.index-1] = c, p)
: (p[c.index-1] = c, p),[]);
}
console.log(deleteObjectsFromArray(item,2,4));
Suppose I have the following arrays:
var first = [
{ id: 1, name: 'first' },
{ id: 2, name: 'second' },
{ id: 3, name: 'third' }
]
var second = [
{ id: 2, field: 'foo2' },
{ id: 3, field: 'foo3' },
{ id: 4, field: 'foo4' }
]
var third = [
{ id: 2, data: 'some2' },
{ id: 5, data: 'some5' },
{ id: 6, data: 'some6' }
]
I want to merge them to get the following result:
var result = [
{ id: 1, name: 'first', field: undefined, data: undefined },
{ id: 2, name: 'second', field: 'foo2', data: 'some2' },
{ id: 3, name: 'third', field: 'foo3', data: undefined },
{ id: 4, name: undefined, field: 'foo4', data: undefined },
{ id: 5, name: undefined, field: undefined, data: 'some5' },
{ id: 6, name: undefined, field: undefined, data: 'some6' }
]
How could I do it with JavaScript?
You should get all existed keys and after create new Objects with fill "empty" keys:
function mergeArrays(){
var keys = {};
//save all existed keys
for(var i=arguments.length;--i;){
for(var j=arguments[i].length;--j;){
for(var key in arguments[i][j]){
keys[key] = true;
}
}
}
var res = [];
for(var i=arguments.length;--i;){
for(var j=arguments[i].length;--j;){
//set clone of object
var clone = JSON.parse(JSON.stringify(arguments[i][j]));
for(var key in keys){
if(!(key in clone)){
clone[key] = undefined;
}
}
res.push(clone);
}
}
return res;
}
https://jsfiddle.net/x3b0tk3g/
There is no simple solution for what you want. Here is my suggestion.
var first = [
{ id: 1, name: 'first' },
{ id: 2, name: 'second' },
{ id: 3, name: 'third' }
]
var second = [
{ id: 2, filed: 'foo2' },
{ id: 3, field: 'foo3' },
{ id: 4, field: 'foo4' }
];
var third = [
{ id: 2, data: 'some2' },
{ id: 4, data: 'some4' },
{ id: 6, data: 'some6' }
];
var result = {};
first.concat(second,third).forEach(function(item){
var id = item.id;
var row = result[id];
if(!row){
result[id] = item;
return;
}
for(var column in item){
row[column] = item[column];
}
});
var finalResult = Object.keys(result).map(function(id){
return result[id];
});
console.log(finalResult);
fiddle: http://jsfiddle.net/bs20jvnj/2/
function getByProperty(arr, propName, propValue) {
for (var i = 0; i < arr.length; i++) {
if (arr[i][propName] == propValue) return arr[i];
}
}
var limit = first.length + second.length + third.length;
var res = [];
for (var i = 1; i < limit; i++) {
var x = $.extend({}, getByProperty(first, "id", i), getByProperty(second, "id", i), getByProperty(third, "id", i));
console.log(x["id"]);
if (x["id"] === undefined) x["id"] = i;
res.push(x);
}
console.log(res);
There's probably a shorter way to solve this, but this covers all the steps, including ensuring that there are default properties that are undefined if not found. It also takes any number of input arrays, and you can specify what default keys you require if they're not already covered by the keys in the existing objects, so pretty future-proof for your needs.
// merges the key/values of two objects
function merge(a, b) {
var key;
if (a && b) {
for (key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
}
return a;
}
function concatenate() {
var result = [];
var args = arguments[0];
for (var i = 0, l = args.length; i < l; i++) {
result = result.concat(args[i]);
}
return result;
}
// return a default object
function getDefault() {
return {
id: undefined,
name: undefined,
data: undefined,
field: undefined
};
}
// loop over the array and check the id. Add the id as a key to
// a temporary pre-filled default object if the key
// doesn't exist, otherwise merge the existing object and the
// new object
function createMergedArray(result) {
var temp = {};
var out = [];
for (var i = 0, l = result.length; i < l; i++) {
var id = result[i].id;
if (!temp[id]) temp[id] = getDefault();
merge(temp[id], result[i]);
}
// loop over the temporary object pushing the values
// into an output array, and return the array
for (var p in temp) {
out.push(temp[p]);
}
return out;
}
function mergeAll() {
// first concatenate the objects into a single array
// and then return the results of merging that array
return createMergedArray(concatenate(arguments));
}
mergeAll(first, second, third);
DEMO
This question already has answers here:
A for-loop that compares two arrays looking for matching values
(4 answers)
Closed 8 years ago.
I have two arrays like
var array1 = [
{
id: '1',
name: 'test'
},
{
id: '2',
name: 'test2'
},
{
id: '3',
name: 'test3'
}
]
var array2=[
{
id: '2',
name: 'test2'
}
]
I want to loop through array 1 and find the same object and add more property in array 1
I have something like
for(var i=0; i < array1.length; i++) {
if(array2[i].id == array1[i].id){
alert('find!')
}
}
I understand my above codes don't work because the index is different. Can someone help me about this issue? Thanks a lot!
It’s time for ECMA5
var array1 = [
{
id: '1',
name: 'test',
foo: {
bar: 'bar',
quux: 'quux'
}
},
{
id: '2',
name: 'test2'
},
{
id: '3',
name: 'test3'
}
];
function equal(objA, objB) {
if(Object.keys(objA).length !== Object.keys(objB).length) {
return false;
}
var areEqual = Object.keys(objA).every(function(key) {
if(typeof objA[key] === "object") {
return equal(objA[key], objB[key]);
}
return objA[key] === objB[key];
});
return areEqual;
}
function hasElement(array, element) {
return array.some(function(el) {
return equal(el, element);
});
}
console.log(hasElement(array1, {
id: '1',
name: 'test',
foo: {
bar: 'bar',
quux: 'quux'
}
}));
Assuming the IDs in array2 are all unique, I would create an object whose keys are the IDs:
var obj2 = {};
for (var i = 0; i < array2.length; i++) {
obj2[array2[i].id] = array2[i];
}
Then I would use this to find matching elements:
for (var i = 0; i < array1.length; i++) {
if (obj2[array1[i].id]) {
alert("find!");
}
}
I've got some nested object data and I want to search it and return the matching object based on the id.
var data = [{id: 0, name: 'Template 0', subComponents:[
{id: 1, name: 'Template 1', subItems:[
{id: 2, name: 'Template 2', subComponents:[{id: 3, name: 'Template 3'}], subItems: [{id: 4, name: 'Template 4'}]}
]}
]}
];
So I want to do something like this
getObjectByKeyValue({id: 3})
and have it return
{id: 3, name: 'Template 3'}
It's sort of got to be done generically because I have subItems, AND subComponents which could each have children.
I tried this using Prototype 1.7 and no luck - I think this just searches an array, and not a tree with it's sub nodes:
data.find(function(s){return s.id == 4;})
Thanks in advance!!!!!!
I went a slightly different route and made the findKey method an Object protype:
Object.prototype.findKey = function(keyObj) {
var p, key, val, tRet;
for (p in keyObj) {
if (keyObj.hasOwnProperty(p)) {
key = p;
val = keyObj[p];
}
}
for (p in this) {
if (p == key) {
if (this[p] == val) {
return this;
}
} else if (this[p] instanceof Object) {
if (this.hasOwnProperty(p)) {
tRet = this[p].findKey(keyObj);
if (tRet) { return tRet; }
}
}
}
return false;
};
Which you would call directly on the data object, passing in the key/value you're looking for:
data.findKey({ id: 3 });
Note that this function allows you to find an object based on any key:
data.findKey({ name: 'Template 0' });
See example → (open console to view result)
Not the best of the and final solution.
But can get you a start for what you are looking...
var data = [{id: 0, name: 'Template 0', subComponents:[
{id: 1, name: 'Template 1', subItems:[
{id: 2, name: 'Template 2', subComponents:[{id: 3, name: 'Template 3'}], subItems: [{id: 4, name: 'Template 4'}]}
]}
]}
];
function returnObject(data,key,parent){
for(var v in data){
var d = data[v];
if(d==key){
return parent[0];
}
if(d instanceof Object){
return returnObject(d,key,data);
};
}
}
function returnObjectWrapper(datavar,key){
return returnObject(datavar,key.id)
}
returnObjectWrapper(data,{id:3})
Please see my solution below or http://jsfiddle.net/8Y6zq/:
var findByKey = function (obj, key) {
var j, key = key || '', obj = obj || {}, keys = key.split("."),
sObj = [], ssObj = [], isSelector = !!(keys.length > 0);
var findKey = function (obj, key) {
var k;
for (k in obj) {
if (k === key) {
sObj.push(obj[k]);
} else if (typeof obj[k] == 'object') {
findKey(obj[k], key);
}
}
};
if (isSelector) {
var nKey = keys.shift();
findKey(obj, nKey);
while (keys.length > 0) {
nKey = keys.shift();
if (sObj.length > 0) {
ssObj = sObj.slice(0), sObj = [];
for (j in ssObj) {
findKey(ssObj[j], nKey);
}
}
}
} else {
findKey(obj, key);
}
// return occurrences of key in array
return (sObj.length === 1) ? sObj.pop() : sObj;
};
var data = [
{id: 0, name: 'Template 0', subComponents: [
{id: 1, name: 'Template 1', subItems: [
{id: 2, name: 'Template 2', subComponents: [
{id: 3, name: 'Template 3'}
], subItems: [
{id: 4, name: 'Template 4'}
]}
]}
]},
{subComponents:{
comp1:'comp1 value',
comp2:'comp2 value',
}}
];
alert(JSON.stringify(findByKey(data, 'subComponents')));
alert(JSON.stringify(findByKey(data, 'subComponents.comp1')));
alert(JSON.stringify(findByKey(data, 'subComponents.comp2')));
In this implementation we can use search by KEY or SELECTOR (eg. "<paren_key>.<child_key_1>.<child_key_2>. ... <child_key_N>")
In case you really need a search through your tree data return all results (not a unique key), here is a little modified version of mVChr's answer:
Object.prototype.findKey = function (keyObj) {
var p, key, val, tRet;
var arr = [];
for (p in keyObj) {
if (keyObj.hasOwnProperty(p)) {
key = p;
val = keyObj[p];
}
}
for (p in this) {
if (p == key) {
if (this[p] == val) {
arr.push(this);
}
} else if (this[p] instanceof Object) {
if (this.hasOwnProperty(p)) {
tRet = this[p].findKey(keyObj);
if (tRet) {
for (var i = 0; i < tRet.length; i++)
arr.push(tRet[i]);
}
}
}
}
if (arr.length > 0)
return arr;
else
return false;
};
We now use object-scan for data processing tasks like this. It's pretty powerful once you wrap your head around how to use it. Here is how you'd answer your questions
// const objectScan = require('object-scan');
const find = (id, input) => objectScan(['**'], {
abort: true,
rtn: 'value',
filterFn: ({ value }) => value.id === id
})(input);
const data = [{ id: 0, name: 'Template 0', subComponents: [{ id: 1, name: 'Template 1', subItems: [{ id: 2, name: 'Template 2', subComponents: [{ id: 3, name: 'Template 3' }], subItems: [{ id: 4, name: 'Template 4' }] }] }] }];
console.log(find(3, data));
// => { id: 3, name: 'Template 3' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan