In Javascript, how to merge array of objects? - javascript

var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}];
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}];
What's the fastest way to have (no duplicates, name is the identifier):
[{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}, { "name" : "buz" , "age" : "35"}];
With and without jquery if possible.

Here's a general purpose function that would merge an arbitrary number of arrays, preventing duplicates of the passed in key.
As it is merging, it creates a temporary index of the names used so far and only merges new elements that have a unique name. This temporary index should be much faster than a linear search through the results, particularly as the arrays get large. As a feature this scheme, it filters all duplicates, even duplicates that might be in one of the source arrays.
If an element does not have the keyName, it is skipped (though that logic could be reversed if you want depending upon what error handling you want for that):
var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}];
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}];
function mergeArrays(keyName /* pass arrays as additional arguments */) {
var index = {}, i, len, merge = [], arr, name;
for (var j = 1; j < arguments.length; j++) {
arr = arguments[j];
for (i = 0, len = arr.length; i < len; i++) {
name = arr[i][keyName];
if ((typeof name != "undefined") && !(name in index)) {
index[name] = true;
merge.push(arr[i]);
}
}
}
return(merge);
}
var merged = mergeArrays("name", array1, array2);
// Returns:
// [{"name":"foo","age":"22"},{"name":"bar","age":"33"},{"name":"buz","age":"35"}]
You can see it work here: http://jsfiddle.net/jfriend00/8WfFW/
When this algorithm is run against the Matt algorithm in jsperf using larger arrays, this algorithm is around 20x faster:

What you have are completely different objects, and there is nothing built into JavaScript to detect identical objects; i.e. objects which have the same attributes, so we have to write our own function:
function merge(set1, set2) {
// Already put the elements of set1 in the result array
// see Array.slice
var result = set1.slice(0);
// Utility function which iterates over the elements in result
// and returns true if an element with the same name already
// exists. false otherwise
function exists(obj) {
for (var i=0;i<result.length;i++) {
if (result[i].name == obj.name) {
return true;
}
}
return false;
}
// Now simply iterate over the second set and add elements
// which aren't there already using our exists() function.
for (var i=0;i<set2.length;i++) {
if (!exists(set2[i])) {
result.push(set2[i]);
}
}
return result;
}
You'd then call it with;
var result = merge(array1, array2);
To become more confident with object equality try the following experiment;
var a = { "test": 1 };
var b = { "test": 1 };
var aClone = a;
alert(a == a); // true
alert(a == b); // false
alert(a == aClone); // true

I don't think that plain javascript offers anything better than iterating the array's and manually implementing the logic for that. What I would advice is to use the awesome underscore.js library that provides many functional-like facilities to handle arrays and collections in general; to solve your problem for example this could work:
http://documentcloud.github.com/underscore/#union
jQuery is another option, but it is more a DOM-manipulation browser-oriented library, while underscore is made to deal with these kind of problems.

The first way I can think of:
array3 = [];
for(object in array1) {
var match=false;
for(already in array3) {
if (already==object) {
match=true;
break; } }
if (match) array3.push(object); }

Related

Replace/change item with same key

Using underscore and I have an object array like so -
myObj = [{"car" : "red" },{"tree" : "green"}];
and I am being passed a new object that I need to find and overwrite an object with the same key, so I would be sent like
{"car" : "blue" };
And I have to take the original object and change the car to blue. Is this possible with underscore? Thanks!
Edit - just to be clear, I am being given the {"car" : "blue"} and I need to compare it to the original object and find the "car" and replace it with the new value. Thanks!
Sure. Assuming all of your objects only have one key:
var myArr = [ { "car" : "red" }, { "tree": "green" } ];
// First, find out the name of the key you're going to replace
var newObj = { "car": "blue" };
var newObjKey = Object.keys(newObj)[0]; // => "car"
// Next, get the index of the array item that has the key
var index = _.findIndex(myArr, function(obj) { return newObjKey in obj; });
// => 0
// Finally, replace the value
myArr[index][newObjKey] = newObj[newObjKey];
FYI findIndex is an Underscore.js 1.8 feature. If you're using an older version of Underscore, you'll need to replace that line with something like this:
var index;
_.find(myObj, function(obj, idx) {
if("car" in obj) {
index = idx;
return true;
}
});
another way you can do this would be as follows
myObj = [{"car" : "red" },{"tree" : "green"}];
let object2 = {"car": "blue"}
for(let obj of myObj){
for(let key in obj){
object2[key] ? obj[key] = object2[key] : ''
}
}
That should dynamically replace anything from object2 which matches a key in an object within the array myObj
don't need any extra libraries or crazy variables :) Just good old fashioned javascript
EDIT Might not be a bad idea to include something like if(object2 && Object.keys(object2)){} around the for loop just to ensure that the object2 isn't empty/undefined

In Javascript, how can I Rename/Renumber a set of properties?

This is one of those questions I'm ashamed to even ask, but I'm working with an external JSON source and I'm forced to do something ugly. So here goes...
I have 'dirty' Javascript object, with property names containing a number at their end:
{ "Friend1" : "Bob",
"Friend6" : "Fred",
"Friend632" : "Gonzo",
"FriendFinder1" : "Dolly",
"FriendFinder4294" : "Jan"
}
I'm trying to figure out a way to clean-up/"zero-index" these property names so the object would look like:
{ "Friend0" : "Bob",
"Friend1" : "Fred",
"Friend2" : "Gonzo",
"FriendFinder0" : "Dolly",
"FriendFinder1" : "Jan"
}
I'm referencing this indexOf/Regex code:
Is there a version of JavaScript's String.indexOf() that allows for regular expressions?
Any strategies you could recommend for doing this? I'll post where I'm at in a bit. Many thanks!
Take the "base" of a key and append items with a common base to an array using the original index. (This produces a sparse array.) Then stretch it out again by enumerating each item with a common base into a new key with 'base'+enumeratedindex.
The trick here is to use a method like forEach to enumerate the array--this will only visit assigned items in a sparse array, allowing you to determine the sort order just by using the original index-part of the key.
If you don't have access to forEach, you can accomplish a similar task by including the key in the array items. Instead of an intermediate array like this:
{Friend: [undefined, "Bob", undefined, undefined, undefined, undefined, "Fred"]}
You have one like this:
{Friend: [[6, 'Fred'],[1, 'Bob']]}
Then you sort the array and visit each item in a foreach loop, extracting the second item.
Here is code:
function rekey(obj) {
var rekey = /^(.*?)(\d+)$/;
var nestedobj = {}, newobj = {};
var key, basekeyrv, newkey, oldidx, newidx;
function basekey(key) {
return rekey.exec(key).splice(1);
}
for (key in obj) {
if (obj.hasOwnProperty(key)) {
basekeyrv = basekey(key);
newkey = basekeyrv[0];
oldidx = parseInt(basekeyrv[1], 10);
if (!nestedobj[newkey]) {
nestedobj[newkey] = [];
}
nestedobj[newkey][oldidx] = obj[key];
}
}
for (key in nestedobj) {
if (nestedobj.hasOwnProperty(key)) {
newidx = 0;
nestedobj[key].forEach(function(item){
newobj[key+newidx++] = item;
});
}
}
return newobj;
}
rekey({
"Friend1" : "Bob",
"Friend6" : "Fred",
"Friend632" : "Gonzo",
"FriendFinder1" : "Dolly",
"FriendFinder4294" : "Jan"
});
produces
{Friend0: "Bob",
Friend1: "Fred",
Friend2: "Gonzo",
FriendFinder0: "Dolly",
FriendFinder1: "Jan"}
Alternatively, without using forEach:
function rekey(obj) {
var rekey = /^(.*?)(\d+)$/;
var nestedobj = {}, newobj = {};
var key, basekeyrv, newkey, oldidx, newidx;
function basekey(key) {
return rekey.exec(key).splice(1);
}
for (key in obj) {
if (obj.hasOwnProperty(key)) {
basekeyrv = basekey(key);
newkey = basekeyrv[0];
oldidx = parseInt(basekeyrv[1], 10);
if (!nestedobj[newkey]) {
nestedobj[newkey] = [];
}
nestedobj[newkey].push([oldidx, obj[key]]);
}
}
for (key in nestedobj) {
if (nestedobj.hasOwnProperty(key)) {
nestedobj[key].sort();
for (newidx = 0; newidx < nestedobj[key].length; newidx++) {
newobj[key+newidx] = nestedobj[key][newidx][1];
}
}
}
return newobj;
}
Could you try doing the following:
{
friend: new Array(),
friendFinder: new Array()
}
then you can:
friend.push() - Add to array
var index = friend.indexOf("Bob") - find in array
friend.splice(index, 1) - remove from the array at index the 1 is for the number to remove.

How to merge multiple objects in javascript? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have the following JSON object array in javascript :
[{ "AuthorName" : "Abc", "BookName" : "book-1" }]
[{ "AuthorName" : "Abc", "BookName" : "book-2" }]
[{ "AuthorName" : "Abc", "BookName" : "book-3" }]
[{ "AuthorName" : "Abc", "BookName" : "book-4" }]
Now I want to create a single JSON object from the above JSON objects array. The newly created single JSON object contains 2 properties: AuthorName and BooKName array. I am trying to achieve something like this:
{ "AuthorName" : "Abc", "Book" : ['book-1', 'book-2', 'book-3', 'book-4'] }
Now my question is, how can I achive this efficiently and with writing minimum code in javascript?
var obj = {};
for(var i=0; i<myArray.length; i++) {
if(obj[myArray[i].AuthorName] == null)
obj[myArray[i].AuthorName] = [];
obj[myArray[i].AuthorName].push(myArray[i].BookName)
}
Hopefully, this will help:
var bookSort = function (bookarray) {
var i,
book,
authorArray = [],
il = bookarray.length,
j,
jl,
authorInArray;
for (i = 0; i < il; i++) {
authorInArray= false;
jl = authorArray.length;
book = bookArray[i];
for (j = 0; j < jl; j++) {
if (book.AuthorName = authorArray[j].AuthorName) {
authorInArray= true;
authorArray[j].BookName.push(book.BookName);
break;
}
}
if (!authorInArray) {
authorArray.push({AuthorName: book.AuthorName, BookName: [book.BookName]});
}
}
return authorArray;
};
Seems like you need a function that combines multiple objects.
If you create a general purpose function that does this, you can reuse it. I would discourage you from creating a solution with things like authorArray etc hard coded into it.
Let's create a function that takes multiple objects and combines them. Let's keep it simple and assume the objects look like the ones from your question. In other words the objects to combine will simply be a flat list of name value pairs. The values will either be a string or an array of strings.
jsFiddle Demo
// A function that combines multiple object.
// The original objects are made of name value pairs where the values are strings.
// If - for a key - the values are the same, the value is kept
// If - for a kye - the values are different, and array is created and the values pushed to it
// after this all new values are added to the array if not already there.
var combineObjects = function() {
// see how many object are to be combined
var length = arguments.length,
i,
// Create a new empty object that will be returned
newObject = {},
objectIn,
prop,
temp,
ii,
alreadyExists;
// Go through all passed in object... combinging them
for (i = 0; i < length; ++i) {
objectIn = arguments[i];
for (prop in objectIn) {
if (objectIn.hasOwnProperty(prop)) {
// Check if the prop exisits
if (newObject[prop]) {
// Check if the prop is a single or multiple (array)
if (Object.prototype.toString.call( newObject[prop] ) === '[object Array]') {
// Multiple
// Check if element is in array
alreadyExists = false;
for (ii = 0; ii < newObject[prop].length; ++ii) {
if (newObject[prop][ii] === objectIn[prop]) {
alreadyExists = true;
break;
}
}
if (! alreadyExists) {
newObject[prop].push(objectIn[prop]);
}
} else {
// Single
if (newObject[prop] !== objectIn[prop]) {
temp = newObject[prop];
newObject[prop] = [temp, objectIn[prop]];
}
}
} else {
newObject[prop] = objectIn[prop];
}
}
}
}
// Alert for testing
alert(JSON.stringify(newObject));
return newObject;
};
It looks like those are just four seperate arrays containing objects.
If you put those four seperate arrays inside another array so they can be iterated, like so:
var a = [
[{ AuthorName : 'Abc', BookName : 'book-1'}],
[{ AuthorName : 'Abc', BookName : 'book-2'}],
[{ AuthorName : 'Abc', BookName : 'book-3'}],
[{ AuthorName : 'Abc', BookName : 'book-4'}]
];
I'd just do:
var new_array = [],
temp_obj = {};
$.each(a, function(i,e) {
var author = e[0].AuthorName,
book = e[0].BookName;
temp_obj[author] ? temp_obj[author].push(book) : temp_obj[author] = [book];
});
$.each(temp_obj, function(author,books) {
var obj = {AuthorName: author, BookName : books};
new_array.push(obj);
});
//new_array is now = [{ AuthorName : 'Abc', BookName : ['book-1', 'book-2', 'book-3', 'book-4'] }]
FIDDLE
and it would sort out more authors and books etc. aswell ?
PROOF
Not sure what you are after. Maybe this will work for you:
var books = [
[{ "AuthorName" : "Abc", "BookName" : "book-1" }],
[{ "AuthorName" : "Abc", "BookName" : "book-2" }],
[{ "AuthorName" : "Abc", "BookName" : "book-3" }],
[{ "AuthorName" : "Abc", "BookName" : "book-4" }]
];
// First book in the array
var first = books[0][0];
// Add BookName property to the first book object (BookNames would be a better name)
first.BookName = books.map(function(book, n) {
return book[0].BookName;
});
/*
Or, use jQuery.map if you got a older browser that don't support the Array.map function
$.map(books, function(book, n) {
return book[0].BookName;
});
*/
// first is now:
{ AuthorName : "Abc", BookName : ['book-1', 'book-2', 'book-3', 'book-4'] }

Find length of json string

I have following Jsonstring
var j = { "name": "John" };
alert(j.length);
it alerts : undefined, How can i find the length of json Array object??
Thanks
Lets start with the json string:
var jsonString = '{"name":"John"}';
you can easily determine its length:
alert("The string has "+jsonString.length+" characters"); // will alert 15
Then parse it to an object:
var jsonObject = JSON.parse(jsonString);
A JavaScript Object is not an Array and has no length. If you want to know how many properties it has, you will need to count them:
var propertyNames = Object.keys(jsonObject);
alert("There are "+propertyNames.length+" properties in the object"); // will alert 1
If Object.keys, the function to get an Array with the (own) property names from an Object, is not available in your environment (older browsers etc.), you will need to count manually:
var props = 0;
for (var key in jsonObject) {
// if (j.hasOwnProperty(k))
/* is only needed when your object would inherit other enumerable
properties from a prototype object */
props++;
}
alert("Iterated over "+props+" properties"); // will alert 1
Another way of doing this is to use the later JSON.stringify method which will give you an object (a string) on which you can use the length property:
var x = JSON.stringify({ "name" : "John" });
alert(x.length);
Working Example
function getObjectSize(o) {
var c = 0;
for (var k in o)
if (o.hasOwnProperty(k)) ++c;
return c;
}
var j = { "name": "John" };
alert(getObjectSize(j)); // 1
There is no json Array object in javascrit. j is just an object in javascript.
If you means the number of properties the object has(exclude the prototype's), you could count it by the below way:
var length = 0;
for (var k in j) {
if (j.hasOwnProperty(k)) {
length++;
}
}
alert(length);
An alternate in Jquery:
var myObject = {"jsonObj" : [
{
"content" : [
{"name" : "John"},
]
}
]
}
$.each(myObject.jsonObj, function() {
alert(this.content.length);
});
DEMO

Add JavaScript object to JavaScript object

I'd like to have JavaScript objects within another JavaScript object as such:
Issues:
- {"ID" : "1", "Name" : "Missing Documentation", "Notes" : "Issue1 Notes"}
- {"ID" : "2", "Name" : "Software Bug", "Notes" : "Issue2 Notes, blah, blah"}
- {"ID" : "2", "Name" : "System Not Ready", "Notes" : "Issue3 Notes, etc"}
// etc...
So, I'd like "Issues" to hold each of these JavaScript objects, so that I can just say Issues[0].Name, or Issues[2].ID, etc.
I've created the outer Issues JavaScript object:
var jsonIssues = {};
I'm to the point where I need to add a JavaScript object to it, but don't know how. I'd like to be able to say:
Issues<code here>.Name = "Missing Documentation";
Issues<code here>.ID = "1";
Issues<code here>.Notes = "Notes, notes notes";
Is there any way to do this? Thanks.
UPDATE: Per answers given, declared an array, and am pushing JavaScript objects on as needed:
var jsonArray_Issues = new Array();
jsonArray_Issues.push( { "ID" : id, "Name" : name, "Notes" : notes } );
Thanks for the responses.
var jsonIssues = []; // new Array
jsonIssues.push( { ID:1, "Name":"whatever" } );
// "push" some more here
As my first object is a native JavaScript object (used like a list of objects), push didn't work in my scenario, but I resolved it by adding new key as follows:
MyObjList['newKey'] = obj;
In addition to this, may be useful to know how to delete the same object as inserted before:
delete MyObjList['newKey'][id];
Hope it helps someone as it helped me.
var jsonIssues = [
{ID:'1',Name:'Some name',Notes:'NOTES'},
{ID:'2',Name:'Some name 2',Notes:'NOTES 2'}
];
If you want to add to the array then you can do this
jsonIssues[jsonIssues.length] = {ID:'3',Name:'Some name 3',Notes:'NOTES 3'};
Or you can use the push technique that the other guy posted, which is also good.
// Merge object2 into object1, recursively
$.extend( true, object1, object2 );
// Merge object2 into object1
$.extend( object1, object2 );
https://api.jquery.com/jquery.extend/
If it's not an array of object you can do this:
let student= {
name : 'Mr. Anderson',
id: 35
}
student['grade'] = 10; //for a property.
Result:
student= {
name : 'Mr. Anderson',
id: 35,
grade:10
}
You also can add an object:
let student= {
personalData:{
//personal data key-value
}
}
let academicData = {
//academic data key-value
}
student['academicData'] = academicData;
Result:
student{
personalData{},
academicData{}
}
jsonIssues = [...jsonIssues,{ID:'3',Name:'name 3',Notes:'NOTES 3'}]
If you have properties in first obj and you have to add your objs to it, then Object.assign() will erase it.
To avoid this loss I've written a function below. Be aware, it copies nested objs by refference.
First you should add all objs you want to add to your's obj to an arr. You can do it easily by arr.push(). Then just use the Fn.
function addMyObjs (objInit, arrWithObjs) {
let map = new Map();
for (let [key, value] of Object.entries(objInit)) {
map.set(key, value);
}
arrWithObjs.forEach((item) => {
for (let [key, value] of Object.entries(item)) {
map.set(key, value);
}
});
return Object.fromEntries(map);
}
let objSecond = {id: 2,};
let obj = {
name: "Tolya",
age: 33,
sex: "man",
};
let obj3 = {"fruits": {"apples": true, "plums": false,}};
let arr = [obj, obj3];
objSecond = addMyObjs(objSecond, arr);

Categories

Resources