How to retrieve a dynamic variable from an object - javascript

I have a js object which looks like this:
var detailsArray = [
{a0 :1,
b0 :'A'},
{a1 :2,
b1 :'B'},
{a2 :3,
b2 :'C'},
{a3 :4,
b3 :'D'}];
This is how the object is created from the server side. On the client side I want to retrieve the value of all 'a's and add them to an array. The problem is that the variable name is changing depending on the index number. I have tried using underscore.js to do something like this:
var variableA = new Array();
for(var i = 0;i<detailsArray.length;i++){
var temp = 'a' + i;
variableA[i] = _.pluck(detailsArray,temp);
}
But this does not work. Can anyone tell how to get the values??

There is two ways for accessing properties of object in javascript : using the dot like you just done, or using the array syntax style.
var obj = {'a':5};
obj.a
obj['a']
So with your code, this would give this :
var variableA = new Array();
for(var i = 0;i<detailsArray.length;i++){
variableA[i] = detailsArray[i]['a' + i];
}

With underscore, you could do:
_.reduce(_.map(detailsArray, function(o, i) {
return o['a' + i];
}), function(a, b) {
return a + b;
});
And with native JS in newer browsers:
detailsArray.map(function(o, i) {
return o['a' + i];
}).reduce(function(a, b) {
return a + b;
});

You can also do it like that:
for (var i = 0; i < detailsArray.length; i++)
alert(eval("detailsArray[" + i + "].a" + i));
The code I provide will alert all the values corresponding to as in the json array, but obviously you can do whatever you want with the values obtained.
Here I am counting that all the keys will be of the kind a smth, but I suppose this is a safe assumption.

here's one possible implementation
var tmp = [];
for (var i = 0; i < detailsArray.length; i++) {
var obj = detailsArray[i]; // current object at index
for (var props in obj) { // iterate properties in current object
if (props.charAt() == "a") { // if starts with a....
tmp.push(obj[props]); // add value to array
break; // stop the property iteration and move to next object
}
}
}
console.log(tmp); // [1,2,3,4]

Related

Javascript - nested loops and indexes

I am trying to build an array that should look like this :
[
[{"name":"Mercury","index":0}],
[{"name":"Mercury","index":1},{"name":"Venus","index":1}],
[{"name":"Mercury","index":2},{"name":"Venus","index":2},{"name":"Earth","index":2}],
...
]
Each element is the concatenation of the previous and a new object, and all the indexes get updated to the latest value (e.g. Mercury's index is 0, then 1, etc.).
I have tried to build this array using the following code :
var b = [];
var buffer = [];
var names = ["Mercury","Venus","Earth"]
for (k=0;k<3;k++){
// This array is necessary because with real data there are multiple elements for each k
var a = [{"name":names[k],"index":0}];
buffer = buffer.concat(a);
// This is where the index of all the elements currently in the
// buffer (should) get(s) updated to the current k
for (n=0;n<buffer.length;n++){
buffer[n].index = k;
}
// Add the buffer to the final array
b.push(buffer);
}
console.log(b);
The final array (b) printed out to the console has the right number of objects in each element, but all the indexes everywhere are equal to the last value of k (2).
I don't understand why this is happening, and don't know how to fix it.
This is happening because every object in the inner array is actually the exact same object as the one stored in the previous outer array's entries - you're only storing references to the object, not copies. When you update the index in the object you're updating it everywhere.
To resolve this, you need to create new objects in each inner iteration, or use an object copying function such as ES6's Object.assign, jQuery's $.extend or Underscore's _.clone.
Here's a version that uses the first approach, and also uses two nested .map calls to produce both the inner (variable length) arrays and the outer array:
var names = ["Mercury","Venus","Earth"];
var b = names.map(function(_, index, a) {
return a.slice(0, index + 1).map(function(name) {
return {name: name, index: index};
});
});
or in ES6:
var names = ["Mercury","Venus","Earth"];
var b = names.map((_, index, a) => a.slice(0, index + 1).map(name => ({name, index})));
Try this:
var names = ["Mercury","Venus","Earth"];
var result = [];
for (var i=0; i<names.length; i++){
var _temp = [];
for(var j=0; j<=i; j++){
_temp.push({
name: names[j],
index:i
});
}
result.push(_temp);
}
console.log(result)
try this simple script:
var b = [];
var names = ["Mercury","Venus","Earth"];
for(var pos = 0; pos < names.length; pos++) {
var current = [];
for(var x = 0; x < pos+1; x++) {
current.push({"name": names[x], "index": pos});
}
b.push(current);
}

Object transformation in javascript

I have an an object I need to transform into a different format
The original:
{"module1":{"mod1":[{"hours":10},{"weeks":2},{"days":15}]},
"module2":{"mod2":[{"cars":1},{"cats":5},{"people":4}]},
}
the desired result :
{"module1":"/mod1/10/2/15","module2":"/mod2/1/5/4" }
Here is my attempt (sorry im still learning this)
function(newUrl){
var encodedUrl = {};
var tempString = "";
console.log(JSON.stringify(newUrl));
for (var p in newUrl) {
tempString = "/" + Object.keys(newUrl[p]);
for (var j in newUrl[p]){
_.each(newUrl[p][j], function(obj){
tempString += "/" + _.values(obj);
});
encodedUrl[p] = tempString;
console.log(encodedUrl);
}
}
}
So, I think i was able to make the string correctly. Hoever it only seems to be working the first time around. it's logging in a weird pattern
Object {module1: "/mod1/10/2/15"}
Object {module1: "/mod1///"}
Object {module1: "/mod1///", module2: "/mod2/1/5/4"}
I think i have something wrong in my logic parsing this, I cannot pinpoint it though. Would love a second pair of eyes to help. Thanks!
You have to loop over the properties of each object in turn, extracting the property names and values. There is also an array, so you have to loop over that too.
4 nested loops.
function transformObj(obj) {
var tObj, tStr, tArr, aObj, result = {};
// For each own property in the object, e.g. 'module1'
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
// Transorm the value
tObj = obj[p];
tStr = '';
// For each property in that object, e.g. 'mod1'
for (var q in tObj) {
if (tObj.hasOwnProperty(q)) {
tStr = '/' + q;
tArr = tObj[q];
// for each member of the array
for (var i=0, iLen=tArr.length; i<iLen; i++) {
aObj = tArr[i]
// for each property of each member, e.g. hours, weeks days
for (var r in aObj) {
if (aObj.hasOwnProperty(r)) {
tStr += '/' + aObj[r];
}
}
}
}
}
// Assign transformed value to result object
result[p] = tStr;
}
}
return result;
}
var obj = {"module1":{"mod1":[{"hours":10},{"weeks":2},{"days":15}]},
"module2":{"mod2":[{"cars":1},{"cats":5},{"people":4}]},
};
console.log(JSON.stringify(transformObj(obj)));
// {"module1":"/mod1/10/2/15","module2":"/mod2/1/5/4"}
You can replace the for..in and hasOwnProperty parts with Object.keys(...).forEach(...) to reduce the code a bit, but likely increase the complexity.
Note that the order that properties are returned by for..in and Object.keys will be the same but perhaps not necessarily as you expect, and may be different from browser to browser, so you can only expect consistent results when each object has one property.
There's probably a shorter way, but it seems that your object is sort of complex.
Object.keys(obj).reduce(function(newObj, key, index) {
var module = obj[key];
var moduleKey = 'mod' + (index+1);
var arr = module[moduleKey].map(function(o){return o[Object.keys(o)[0]]}).join('/');
newObj[key] = "/" + moduleKey + "/" + arr
return newObj
}, {});

Copying element of existing array to a a new array without using splice?

I'm currently doing some coursework for university. I am trying to copy an individual value of an old array to a new array, then setting the old arrays value to 0. Obviously if i just assign the value to the new array, then alter the old arrays value, it will overwrite the new array too.
I am not allowed to use the function splice().
here is my code:
function rankedScores(web, pattern) {
var v = urlScores(web, pattern);
var sorted = [];
var maxIndex = 0;
while (sorted.length < v.length) {
for (var i = 0; i < v.length; i += 1) {
if (v[i].score > v[maxIndex].score) {
maxIndex = i
}
}
sorted[sorted.length] = v[maxIndex];
v[maxIndex].score = 0;
maxIndex = 0;
}
alert(sorted[0].url + ' ' + sorted[0].score)
alert(sorted[1].url + ' ' + sorted[1].score)
alert(sorted[2].url + ' ' + sorted[2].score)
}
If i do this it returns the correct URL value, but all the score values are 0.
Any ideas on how i can stop the arrays from pointing to the same memory location?
Ive tried using a for loop as ive seen this does a shallow copy, but it didnt work
Cheers.
Replace:
sorted[sorted.length] = v[maxIndex];
v[maxIndex].score = 0;
with:
// ...
var clone = {};
for(var i in v[maxIndex])
clone[i] = v[maxIndex][i];
sorted[sorted.length] = clone;
v[maxIndex].score = 0;
// ...
Of course, you haven't stated how deep your objects are - I assume they are simple key:value maps but this should be enough to steer you in the right direction.

Javascript: Loop through unknown number of object literals

I have a list of objects all named in this fashion:
var p1 = {};
var p2 = {};
p1.name = "john";
p1.hobby = "collects stamps";
p2.name = "jane";
p2.hobby = "collects antiques";
I know how to loop through p1 and p2 to collect the properties, provided I know how many of these p object literals there are. Here's my problem, I don't always know how many of these p object literals there will be. Sometimes it goes up to p2, sometimes it goes up to p20.
Is there a way to loop through objects if I know they all share the same prefix?
Edit: I can't change how I'm getting the list of objects. It's given to me in that format...
If we make the following assumptions:
The objects are global
The number suffixes are sequential
...then the following works:
for (var i = 1; window["p" + i] !== undefined; i++) {
console.log(window["p" + i]); // loop over each object here
}
You should have them in an Array referenced by a single variable.
var p = [];
p.push({
name:"john",
hobby:"collects stamps"
}, {
name:"jane",
hobby:"collects antiques"
});
Then you'd loop the Array, and enumerate each object...
for( var i = 0; i < p.length; i++ ) {
for( var n in p[i] ) {
console.log( p[i][n] );
}
}
EDIT:
It seems from a comment that these may be arriving as individual variable.
If they're global variables, and if they always have the same p1 naming, then you can access them as properties of the global window object.
var obj;
for( var i = 1; obj = window['p' + i]; i++ ) {
if( typeof obj === 'object' ) {
for( var n in obj ) {
console.log( obj[n] );
}
}
}
This loop will run until a p(n) global returns a falsey value.
So as long as a truthy value is found, and its typeof is 'object', you'll iterate that object.
If you have all your data stored in a variable , or a few variables you can push it into the array.
var data = "....JSON";
var a = [];
a.push(data);
Push keeps adding stuff into the array in basic sense.
You could also pop to remove the last pushed data.
Take a look at the other methods here:
http://www.w3schools.com/jsref/jsref_obj_array.asp
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
Why don't you just store them all in one top-level object literal? It will make it easier to enumerate through them.
EG:
var MyObj = {
p1: {},
p2: {}
};
etc..
[edit]
If they are local vars, are you can't change the format of this data, you might have to use eval.
Don't shoot me:
var p1 = {};
var p2 = {};
p1.name = "john";
p1.hobby = "collects stamps";
p2.name = "jane";
p2.hobby = "collects antiques";
var found = true, c = 1;
while(found) {
try {
var obj = eval('p' + c);
c++;
console.log(obj);
} catch(e){
found = false;
}
}
I don't suggest using this, I suggest changing the format of the data you are receiving, but this is one possible solution.

JavaScript: convert objects to array of objects

I have thousands of legacy code that stores array information in a non array.
For example:
container.object1 = someobject;
container.object2 = someotherobject;
container.object3 = anotherone;
What I want to have is:
container.objects[1], container.objects[2], container.objects[3] etc.
The 'object' part of the name is constant. The number part is the position it should be in the array.
How do I do this?
Assuming that object1, object2, etc... are sequential (like an array), then you can just iterate through the container object and find all the sequential objectN properties that exist and add them to an array and stop the loop when one is missing.
container.objects = []; // init empty array
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
If you want the first item object1 to be in the [1] spot instead of the more typical [0] spot in the array, then you need to put an empty object into the array's zeroth slot to start with since your example doesn't have an object0 item.
container.objects = [{}]; // init array with first item empty as an empty object
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
An alternate way to do this is by using keys.
var unsorted = objectwithobjects;
var keys = Object.keys(unsorted);
var items = [];
for (var j=0; j < keys.length; j++) {
items[j] = unsorted[keys[j]];
}
You can add an if-statement to check if a key contains 'object' and only add an element to your entry in that case (if 'objectwithobjects' contains other keys you don't want).
That is pretty easy:
var c = { objects: [] };
for (var o in container) {
var n = o.match(/^object(\d+)$/);
if (n) c.objects[n[1]] = container[o];
}
Now c is your new container object, where c.object[1] == container.object1

Categories

Resources