Combine / Extend two objects with condition - javascript

I got two Objects
object = {
id: 1,
Oid: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
name: 'Some name'
}
and
object2 = {
id: 3,
array_ref: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
value1: 'Additional Data',
value2: 'Some other additional data'
}
As you see, the only reference between these Objects is the Oid and the Array_ref. Now I want to bind these Objects together to one where the Oid and the Array_ref matches. In the end I have to do this multiple times (with multiple objects).
Is there some easy way to do this?
This Code is realized in JavaScript using angular partly. I'm not able to use anything else.

You are not using arrays (nor JSON) but objects.
If you want to merge two objets, one solution is to use next Javascript API (ES6) Object.assign method through a polyfill (polyfills give you the ability to use standard APIs that are not yet supported):
var obj1 = {
id: 1,
Oid: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
name: 'Some name'
}
var obj2 = {
id: 3,
array_ref: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
value1: 'Additional Data',
value2: 'Some other additional data'
}
var obj3 = Object.assign({}, obj1, obj2);
console.log(obj3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js"></script>
Which will gives you:
In the above snippet I included a whole es6 polyfill but this polyfill here only contains what you are looking for and is probably better if you want to avoid loading a whole bunch of useless code (I could not easily load it in the snippet).
If you use jQuery or underscore, they also both provides an extend method that you can use instead of a polyfill.
Warning! As you can see, this will actually overwrites any content in obj1 that is also in obj2 with the content of obj2. Here, for example, the resulting object has the id of obj2. If you are looking for a more clever kind of merging, you will need to go for more complicated algorithmic.
If you want to merge only the objects with the same id, I would use underscore:
var objectList = [
{ id: 1, val: "val1", otherVal: "val2" },
{ id: 2, val: "val3" },
{ id: 1, val: "val4", differentVal: "val5" }
];
// group objects by ids
var groups = _.groupBy(objectList, 'id');
// merge the groups
var mergedObjects = _.map(groups, function(objects){
// Adds a new empty object at the beginning of the list
// to avoid modifying the original objects.
// It will be the destination of _.extend.
objects.unshift({});
// use extend with apply so we can provide it an array to be used as arguments
return _.extend.apply(_, objects);
});
console.log(mergedObjects);
<script src="http://underscorejs.org/underscore-min.js"></script>
Notice that some overwriting still can happen (first object's val is overwritten by third object's val here).
Edit: As pointed out in the comment, lodash is likely to be a better solution than underscore. Read here about lodash vs. underscore.

Here's a simple way.
Your object could look like this:
{
'ff2d344e-77e8-43b3-a6f3-bfba577d6abd': {
id: 1,
name: 'Some name'
}
}
And then you access it like this:
object[object2.array_ref]
And you would have all the data you want.
Later on, you can add properties to that object using a for( in ) loop:
var obj = object[object2.array_ref];
for(var k in object2)
{
if( !(k in obj) && object2.hasOwnProperty(k))
{
obj[k] = object2[k];
}
}
This would add the values to the object if they aren't already present.
You could verify other calues by adding conditions to that if.

Related

JS - Merge two subobjects

I am working with objects that have subobjects inside, and I want to merge, for example, these objects:
subType:
type:
name:
contains: "e"
and:
subType:
name:
contains: "A"
The result that I want:
subType:
name:
contains: "A"
type:
name:
contains: "e"
What is the best way to do this? Thanks!
With the spread operator ... you can take all fields of an object. You can use it to create a new object with all fields of the other objects.
In general, something like:
var merged = {...object1.subType, ...object2.subType}
Beware, in case of fields on both objects, the last one is taken (including all its subfields).
Use $.extend() from jquery. Refrence https://api.jquery.com/jquery.extend/
In your case, the code would be like belows:
// solution 1
let merged = $.extend({}, obj1, obj2);
// solution 2
$.extend(obj1, obj2);
let merged = obj1;

setState return empty object [duplicate]

...where each object also has references to other objects within the same array?
When I first came up with this problem I just thought of something like
var clonedNodesArray = nodesArray.clone()
would exist and searched for information on how to clone objects in JavaScript. I did find a question on Stack Overflow (answered by the very same #JohnResig) and he pointed out that with jQuery you could do
var clonedNodesArray = jQuery.extend({}, nodesArray);
to clone an object. I tried this though, and this only copies the references of the objects in the array. So if I
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
the value of both nodesArray[0] and clonedNodesArray[0] will turn out to be "green". Then I tried
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
which deep copies an Object, but I got "too much recursion" and "control stack overflow" messages from both Firebug and Opera Dragonfly respectively.
How would you do it? Is this something that shouldn't even be done? Is there a reusable way of doing this in JavaScript?
Creating a deep copy with structuredClone
The modern way to deep copy an array in JavaScript is to use structuredClone:
array2 = structuredClone(array1);
However, this function is relatively new (Chrome 98, Firefox 94) and is currently only available to about 85% of users, so it's not ready for production yet without a polyfill.
As an alternative, you can use one of the well-supported JSON-based solutions below.
Creating a deep copy with JSON.parse
A general solution, that accounts for all possible objects inside an Array of objects may not be possible.
That said, if your array contains objects that have JSON-serializable content (no functions, no Number.POSITIVE_INFINITY, etc.) one simple way to avoid loops, at a performance cost, is this pure vanilla one-line solution.
let clonedArray = JSON.parse(JSON.stringify(nodesArray))
To summarize the comments below, the primary advantage of this approach is that it also clones the contents of the array, not just the array itself. The primary downsides are its limit of only working on JSON-serializable content, and it's performance is ~30 times slower than the spread method.
If you have shallow objects in the array, and IE6 is acceptable, a better approach is to use the spread operator combined with the .map array operator. For a two levels deep situation (like the array in the Appendix below):
clonedArray = nodesArray.map(a => {return {...a}})
The reasons are two fold: 1) It is much, much faster (see below for a benchmark comparison) and it will also allow any valid object in your array.
*Appendix:
The performance quantification is based on cloning this array of objects a million times:
[{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic1.jpg?raw=true', id: '1', isFavorite: false}, {url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic2.jpg?raw=true', id: '2', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic3.jpg?raw=true', id: '3', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic4.jpg?raw=true', id: '4', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic5.jpg?raw=true', id: '5', isFavorite: true},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic6.jpg?raw=true', id: '6', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic7.jpg?raw=true', id: '7', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic8.jpg?raw=true', id: '8', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic9.jpg?raw=true', id: '9', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic10.jpg?raw=true', id: '10', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic11.jpg?raw=true', id: '11', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic12.jpg?raw=true', id: '12', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic13.jpg?raw=true', id: '13', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic14.jpg?raw=true', id: '14', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic15.jpg?raw=true', id: '15', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic16.jpg?raw=true', id: '16', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic17.jpg?raw=true', id: '17', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic18.jpg?raw=true', id: '18', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic19.jpg?raw=true', id: '19', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic20.jpg?raw=true', id: '20', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic21.jpg?raw=true', id: '21', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic22.jpg?raw=true', id: '22', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic23.jpg?raw=true', id: '23', isFavorite: false}]
either using:
let clonedArray = JSON.parse(JSON.stringify(nodesArray))
or:
clonedArray = nodesArray.map(a => {return {...a}})
The map/spread approach took 0.000466 ms per pass and the JSON.parse and JSON.stringify 0.014771 ms per pass.*
I solved cloning of an array of objects with Object.assign
const newArray = myArray.map(a => Object.assign({}, a));
or even shorter with spread syntax
const newArray = myArray.map(a => ({...a}));
If all you need is a shallow copy, a really easy way is:
new_array = old_array.slice(0);
The issue with your shallow copy is that all the objects aren't cloned. While the references to each object are unique in each array, once you ultimately grab onto it you're dealing with the same object as before. There is nothing wrong with the way you cloned it... the same result would occur using Array.slice().
The reason your deep copy is having problems is because you're ending up with circular object references. Deep will go as deep as it can go, and if you've got a circle, it'll keep going infinitely until the browser faints.
If the data structure cannot be represented as a directed acyclic graph, then I'm not sure you're going to be able to find an all-purpose method for deep cloning. Cyclic graphs provide many tricky corner cases, and since it's not a common operation I doubt anyone has written a full solution (if it's even possible - it might not be! But I have no time to try to write a rigorous proof now.). I found some good comments on the issue on this page.
If you need a deep copy of an Array of Objects with circular references I believe you're going to have to code your own method to handle your specialized data structure, such that it is a multi-pass clone:
On round one, make a clone of all objects that don't reference other objects in the array. Keep a track of each object's origins.
On round two, link the objects together.
If you only need a shallow clone, the best way to do this clone is as follows:
Using the ... ES6 spread operator.
Here's the simplest example:
var clonedObjArray = [...oldObjArray];
This way we spread the array into individual values and put it in a new array with the [] operator.
Here's a longer example that shows the different ways it works:
let objArray = [ {a:1} , {b:2} ];
let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array
console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );
objArray[0] = {c:3};
console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]
This works for me:
var clonedArray = $.map(originalArray, function (obj) {
return $.extend({}, obj);
});
And if you need a deep copy of objects in the array:
var clonedArray = $.map(originalArray, function (obj) {
return $.extend(true, {}, obj);
});
$.evalJSON($.toJSON(origArray));
If you want to implement a deep clone, use JSON.parse(JSON.stringify(your {} or [])):
const myObj ={
a: 1,
b: 2,
b: 3
}
const deepClone = JSON.parse(JSON.stringify(myObj));
deepClone.a = 12;
console.log("deepClone-----"+myObj.a);
const withOutDeepClone = myObj;
withOutDeepClone.a = 12;
console.log("withOutDeepClone----" + myObj.a);
Map will create a new array from the old one (without reference to old one) and inside the map you create a new object and iterate over properties (keys) and assign values from the old Array object to corresponding properties to the new object.
This will create exactly the same array of objects.
let newArray = oldArray.map(a => {
let newObject = {};
Object.keys(a).forEach(propertyKey => {
newObject[propertyKey] = a[propertyKey];
});
return newObject;
});
Lodash has the cloneDeep function for these purposes:
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
I may have a simple way to do this without having to do painful recursion and not knowing all the finer details of the object in question. Using jQuery, simply convert your object to JSON using the jQuery $.toJSON(myObjectArray), then take your JSON string and evaluate it back to an object. BAM! Done, and done! Problem solved. :)
var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));
I'm answering this question because there doesn't seem to be a simple and explicit solution to the problem of "cloning an array of objects in JavaScript":
function deepCopy (arr) {
var out = [];
for (var i = 0, len = arr.length; i < len; i++) {
var item = arr[i];
var obj = {};
for (var k in item) {
obj[k] = item[k];
}
out.push(obj);
}
return out;
}
// test case
var original = [
{'a' : 1},
{'b' : 2}
];
var copy = deepCopy(original);
// change value in copy
copy[0]['a'] = 'not 1';
// original[0]['a'] still equals 1
This solution iterates the array values, iterates the object keys, saving the latter to a new object, and pushes that new object to a new array.
See jsfiddle. Note: a simple .slice() or [].concat() isn't enough for the objects within the array.
This method is very simple and you can modify your clone without modifying the original array.
// Original Array
let array = [{name: 'Rafael'}, {name: 'Matheus'}];
// Cloning Array
let clone = array.map(a => {return {...a}})
// Editing the cloned array
clone[1].name = 'Carlos';
console.log('array', array)
// [{name: 'Rafael'}, {name: 'Matheus'}]
console.log('clone', clone)
// [{name: 'Rafael'}, {name: 'Carlos'}]
As Daniel Lew mentioned, cyclic graphs have some problems. If I had this problem I'd either add special clone() methods to the problematic objects or remember which objects I've already copied.
I'd do it with a variable copyCount which increases by 1 every time you copy in your code. An object that has a lower copyCount than the current copy-process is copied. If not, the copy, that exists already, should be referenced. This makes it necessary to link from the original to its copy.
There is still one problem: Memory. If you have this reference from one object to the other, it's likely that the browser can't free those objects, as they are always referenced from somewhere. You'd have to make a second pass where you set all copy-references to Null. (If you do this, you'd not have to have a copyCount but a boolean isCopied would be enough, as you can reset the value in the second pass.)
jQuery extend is working fine. You just need to specify that you are cloning an array rather than an object (note the [] instead of {} as parameter to the extend method):
var clonedNodesArray = jQuery.extend([], nodesArray);
My approach:
var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;
gives me a nice, clean, deep clone of the original array - with none of the objects referenced back to the original :-)
I use the new ECMAScript 6 Object.assign method:
let oldObject = [1, 3, 5, "test"];
let newObject = Object.assign({}, oldObject);
The first argument of this method is the array to be updated. We pass an empty object, because we want to have a new object.
We can also use this syntax, which is the same but shorter:
let newObject = [...oldObject];
I was pretty frustrated by this problem. Apparently the problem arises when you send in a generic Array to the $.extend method. So, to fix it, I added a little check, and it works perfectly with generic arrays, jQuery arrays, and any objects.
jQuery.extend({
deepclone: function(objThing) {
// return jQuery.extend(true, {}, objThing);
/// Fix for arrays, without this, arrays passed in are returned as OBJECTS! WTF?!?!
if ( jQuery.isArray(objThing) ) {
return jQuery.makeArray( jQuery.deepclone($(objThing)) );
}
return jQuery.extend(true, {}, objThing);
},
});
Invoke using:
var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);
This deeply copies arrays, objects, null and other scalar values, and also deeply copies any properties on non-native functions (which is pretty uncommon but possible). (For efficiency, we do not attempt to copy non-numeric properties on arrays.)
function deepClone (item) {
if (Array.isArray(item)) {
var newArr = [];
for (var i = item.length; i-- > 0;) {
newArr[i] = deepClone(item[i]);
}
return newArr;
}
if (typeof item === 'function' && !(/\(\) \{ \[native/).test(item.toString())) {
var obj;
eval('obj = '+ item.toString());
for (var k in item) {
obj[k] = deepClone(item[k]);
}
return obj;
}
if (item && typeof item === 'object') {
var obj = {};
for (var k in item) {
obj[k] = deepClone(item[k]);
}
return obj;
}
return item;
}
Array.slice can be used to copy an array or part of an array...
This would work with strings and numbers .. - changing a string in one array would not affect the other - but objects are still just copied by reference, so changes to referenced objects in one array would have an affect on the other array.
Here is an example of a JavaScript undo manager that could be useful for this: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
Forget eval() (it is the most misused feature of JavaScript and makes the code slow) and slice(0) (works for simple data types only)
This is the best solution for me:
Object.prototype.clone = function() {
var myObj = (this instanceof Array) ? [] : {};
for (i in this) {
if (i != 'clone') {
if (this[i] && typeof this[i] == "object") {
myObj[i] = this[i].clone();
}
else
myObj[i] = this[i];
}
}
return myObj;
};
In JavaScript, array and object copy change the original values, so a deep copy is the solution for this.
A deep copy means actually creating a new array and copying over the values, since whatever happens to it will never affect the origin one.
JSON.parse and JSON.stringify is the best and simple way to deep copy. The JSON.stringify() method converts a JavaScript value to a JSON string.The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string.
Deep Clone
let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0
console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]
For more details: Read Here
In 2022, We can use structuredClone to deep copy.
structuredClone(array)
For more details about it click here
We can invent a simple recursive Array method to clone multidimensional arrays. While the objects within the nested arrays keep their reference to the corresponding objects in the source array, arrays won't.
Array.prototype.clone = function(){
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));
With jQuery:
var target = [];
$.each(source, function() {target.push($.extend({}, this));});
I am using Vue.js, so arrays/objects have other code tacked-on for Vue.js functionality. I tried many of the answers given, but I ended up using clone-deep.
person1 = {
name: 'Naved',
last: 'Khan',
clothes: {
jens: 5,
shirts: 10
}
};
person2 = {
name: 'Naved',
last: 'Khan'
};
// first way shallow copy single lavel copy
// const person3 = { ...person1 };
// secound way shallow copy single lavel copy
// const person3 = Object.assign({}, person1);
// third way shallow copy single lavel copy but old
// const person3 = {};
// for (let key in person1) {
// person3[key] = person1[key];
// }
// deep copy with array and object best way
const person3 = JSON.parse(JSON.stringify(person1));
person3.clothes.jens = 20;
console.log(person1);
console.log(person2);
console.log(person3);
The following code will perform a deep copy of objects and arrays recursively:
function deepCopy(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
var out = [], i = 0, len = obj.length;
for ( ; i < len; i++ ) {
out[i] = arguments.callee(obj[i]);
}
return out;
}
if (typeof obj === 'object') {
var out = {}, i;
for ( i in obj ) {
out[i] = arguments.callee(obj[i]);
}
return out;
}
return obj;
}
Source
Some elegant ways for deep cloning in JavaScript:
Type: Object
Copying Objects in JavaScript
 
A vanilla JavaScript method for cloning objects
A clever exploit of the JSON library to deep-clone objects
Using jQuery’s $.extend() function
Using Mootools’ clone() function to clone objects
Here is a my solution. It works for an array of objects or Map. This solution keeps the methods also.
A deep copy means actually creating a new array and copying over the values, since whatever happens to it will never affect the origin one.
This is the best solution for me:
deepCopy(inputObj: any) {
var newObj = inputObj;
if (inputObj && typeof inputObj === "object") {
newObj = Object.prototype.toString.call(inputObj) === "[object Array]" ? [] : {};
for (var i in inputObj) {
newObj[i] = this.deepCopy(inputObj[i]);
}
//For maps
if(Object.prototype.toString.call(inputObj) === "[object Map]"){
newObj = new Map;
inputObj.forEach((v,k) =>{
newObj.set(k,this.deepCopy(v));
});
}
}
return newObj;
}

How to convert data to string

I have data for example like this:
data: [{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}]
And I want to convert them into like this:
data: ['Apple','Microsoft','Google']
Is there a best way to do this? Wherever I am reading, people are using complex logic using loops. So are there alternative methods to doing this?
One way is to use Array.map and replace the object ele.tag with just the value return ele.tag:
var data =
[{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}];
data = data.map(function(ele){ return ele.tag; });
console.log(data);
Or in ES6 you can simply this even more:
data = data.map(ele => ele.tag);
You could use a for-in loop and push the attribute of the object into an array.
var data = [{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}];
var tags = [];
for (prop in data) {
tags.push(data[prop].tag);
}
console.log(tags);
For easier handling let's take the object in the OP's code and assign it to a variable, as follows:
var obj = {"data":[{"tag":'Apple'},{"tag":'Microsoft'},{"tag":'Google'}]};
var {data}= obj; // object destructing ...
var mapped = data.map(function( e ){ return e.tag});
// re-assigning value of object's data property
obj["data"] = mapped;
console.log(obj); // obj.data now pertains to array of strings
The problem described by the OP involves an object whose data property refers to an array of objects, each with a tag property. The OP inquires as to how to revise the data property so that it refers instead to an array of string values corresponding to each object's tag property.
This example makes use of destructuring to access the array of objects. Then, it uses the array's map() method to access every element's tag property and thereby obtain its string value. The beauty of map() is that it performs iteration behind the scenes sparing the user from having to hand-code a loop with the correct logic -- although in functional programming languages instead of using iteration, recursion is more apt to be utilized for this purpose. Finally, the value of the object's data property is reset to contain the specified array of strings.

An object contains a collection of objects - each with an id and name, how do I separate them?

At the moment I have this object:
obj = [object{id: 1, name: test, parentID: 3}, object{id:1, name: another, parentID: 5}, object{id:2, name:something, parentID: 1}].
Ultimately I want an object structured in a different manner.
So that it is object, but if my identifier is 1, it has a collection of names (in this case test, and another). If it is 2, it only shows 'something'.
I can't work out how this should look, probably like so?
obj = [[1,test], [1,another], [2,something]] right?
So that if I call obj[1] I get a multiples back (test, another etc).
Can someone help? I've been fiddling with this for an hour now, I just don't understand.
I built the original object like this:
var obj = Array();
//loop here
var obj = {
id: id,
name: name,
parentID: parentID
};
obj.push(obj);
What did I do wrong? How can I fix this? This got me my object within objects thing, but really I want id's and names within id's and names. My ultimate goal is to iterate through this. So that I only get out the names of anything of a like ID, that way I can use this to populate an array or count
Thus:
if(obj[id] == 1){
//put the name in the new array
}
is my ultimate goal. But I've gotten a bit lost with the initial object creation so now it is a big mess.
Try:
var obj = [{id: 1, name: "Foo"}, {id: 2, name: "Fee"}, {id: 3, name: "Fii"}];
var result = [], item, i = 0;
while(item = obj[i++]){
for(key in item){
if(key === "id") continue; //remove this line if you want to keep the ID also in the array
!result[i] && (result[i] = []);
result[i].push(item[key]);
}
}
console.log(result[1]); // --> ["Foo"]
My take:
var sourceObject=[{id:0,name:'Tahir'},{id:0,name:'Ahmed'},{id:1,name:'David'},{id:1,name:'G'},{id:2,name:'TA'},{id:3,name:'DG'}];
function getNames(id){
var names=[],length=sourceObject.length,i=0;
for(i;i<length;i+=1){
if(sourceObject[i].id===id){
names[names.length]=sourceObject[i].name;
}
}
return names;
}
console.log(getNames(1));
What you want to do is walk the array of objects one time. Each time through, you want to check your new object to see if that id exists yet. If it does, add the name. If not, make a new entry for that id and add an array with one entry. Note, this doesn't handle duplicate names (it just adds it again).
var array = [{id:1, name:"test"},
{id:1, name:"another"},
{id:2, name:"something"}];
var result = {};
array.forEach(function(item) {
if (result[item.id]) {
result[item.id].push(item.name);
}
else {
result[item.id] = [item.name];
}
});
console.log(result[1]);

Use pop() with JavaScript Associative Arrays

How can I do something like the following in JS? I would like to imitate .pop() on an object rather than an array.
var deck = {
'cardK' :'13',
'cardQ' :'12',
'cardAJ':'11'
};
var val = deck.pop();
console.log("Key" + val.key );
console.log("Value" + val.val );
It seems like it's not possible.
.pop is only available on an array. In JavaScript, objects (which are essentially associative arrays) are not ordered like an array, so there is no .pop method.
You could use an array:
var deck = [
{ key: 'cardK', val: 13 },
{ key: 'cardQ', val: 12 },
{ key: 'cardAJ', val: 11 },
];
var val = deck.pop();
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
As suggested by other answers, the best solution here might be to use an array of objects. However you could also create your own pop function that removes a key from an object, for example:
function pop(obj) {
var key = Object.keys(obj).pop();
var result = {key: key, val: obj[key]};
delete obj[key];
return result;
}
var val = pop(deck);
You could add a similar pop function to Object.prototype so that you could do deck.pop(), but I would strongly recommend against that type of design.
You are right, it's not possible. See objects as maps or hash tables, rather than "associative arrays". The properties don't have an order and thus a method such as .pop would not make sense (unless of course it would remove a random property, like Python's dictionaries).
If you want to to use .pop and val.key and val.val, you have to create an array of objects instead:
var deck = [
{key: 'cardK', val: '13'},
{key: 'cardQ', val: '12'},
{key: 'cardAJ', val: '11'}
];
As I'm sure you know, .pop is a prototypal Array method, so you can't use it with Javascript objects.
Calling .pop on an array will remove the last element from the array. However, there isn't a "last" key-value pair with objects, as their order is not ever guaranteed. Despite this, if you don't care about order, you could implement a .pop-like function for use with objects, though, again, it wouldn't remove and return the final key-value pair.
Something like this should do the trick:
function pop(obj) {
for (var key in obj) {
var val = obj[key];
delete obj[key];
return {
'key' : key,
'val' : val,
};
};
};
Combined with your code:
var val = pop(deck);
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
When working with this structure, which can be thought of as an associative array, you need to use different techniques. Things like pop(), slice() and even .length will not work as they do with numeric keyed arrays.
I use string keyed object arrays when searching for the key/value pair needs to happen fast.
Here's a jsPef I just created which shows the benefit of your array structure:
http://jsperf.com/bmcgin-object-array-tests (keep in mind the performance goes way up as the array gets bigger)
Also keep in mind the value can be a number, a string, an array, a function, an object ect...

Categories

Resources