I'm trying to create a new object for each item in an array by looping. The names of the objects should be based on the key of the array.
So for this array:
var arr = new Array(
"some value",
"some other value",
"a third value"
);
Would result in three objects:
alert(object1.value);
alert(object2.value);
alert(object3.value);
The code I have thus far (but isn't working) is:
// Object
function fooBar(value) {
this.value = value;
...
}
// Loop
var len = arr.length;
for (var i = 0; i < len; i++) {
var objectName = object + i;
var objectName = new fooBar(arr[i]);
}
Does what I'm asking for even make sense?
You have to make an array of the objects also
var objs = new Array();
for(var i = 0; i < len; i++) {
objs[i] = new fooBar(arr[i]);
}
alert(objs[0].value);
You can map your array:
var arr = new Array(
"some value",
"some other value",
"a third value"
);
var fooBars = arr.map(function(x) { return new fooBar(x); });
Then you can access each value:
alert(fooBars[0].value);
// etc.
or process them all at once:
fooBars.forEach(function (foo) { alert(foo.value); });
What you're asking for makes sense, but shouldn't be how you're building you JavaScript out.
Technically, there is a way of creating vars with names you build dynamically, but you shouldn't use it as it's slow, and if users are specifying what's in the array, it's unsafe and the feature is being needed in a couple of years, so your old stuff might break in future browsers.
Meanwhile, you could easily do something like:
var obj = {},
arr = [ "one", "two", "three" ],
i = 0,
len = arr.length,
val = "",
name = "";
for (; i < len; i += 1) {
name = "item" + i;
val = arr[i];
obj[name] = val;
}
Now you can call obj.item1; // "two"
If you're really desperate, you can use window as obj so when you're writing stuff in the global scope, you can just write item0; // "one" but this really isn't a great idea, for several reasons (readability, maintainability, likelihood of overwriting somebody else's properties, etc).
If you really want the variable named so, here's a solution
function fooBar(value) {
this.value = value;
}
var arr = new Array(
"some value",
"some other value",
"a third value"
);
(function(context) {
for ( var i = 0; i < arr.length; i++) {
var key = 'object' + ( i + 1 );
this[ key ] = new fooBar( arr[ i ] );
}
}(window));
alert(object1.value);
alert(object2.value);
alert(object3.value);
If you don't want global variables object1 ... just replace the keyword window with this and it will produce local variable to the current scope.
Test it out here: http://jsfiddle.net/bukart/F8ham/1/
Related
Desired:
I have multiple arrays of players, roundWinners, being iterated through in a FOR loop. For each array, I need the MODE of the array (the most frequently occurring value) assigned to a new variable winner.
I am lost as to where to start, so I ask what is the most efficient way to go about accomplishing this?
Example:
for (i = 0; i < numberOf; i++) {
var roundWinners[0] = ["Joe", "Joe", "Bob", "Sue"]
var winner[0] ="Joe";
var roundWinners[1] = ["Joe", "Sue", "Bob", "Sue"]
var winner[1] ="Sue";
var roundWinners[2] = ["Bob", "Bob", "Bob", "Sue"]
var winner[2] ="Bob";
}
Prior to the loop, create an object.
var ArrMode = {};
Then, on each iteration, take the name, and, using it as a property name, see if the object has a property of that name. If so, increment the value of that property.
If not, add that property, setting its value to 1.
After processing the array, then process the object, using a simple replace-if-greater test. Each time you make a replacement, hold the name of that property as the winner.
Once you have processed the whole object, the property name you are holding is the name of the winner.
I don't actually have an answer
One person posted this as a way to iterate through the properties of a JS object, when you do not know the property names at design time:
for (var property in object) {
if (object.hasOwnProperty(property)) {
// do stuff
}
}
You can add a property to a JS object at any time, using:
obj[theName] = theVal; // the name’d be a string, theVal’d be anything
// Like:
var theName = "John";
obj[theName] = 1;
So, you would create an empty object before the loop with a name (like, say "modes"), but no properties
var modes = {};
Then, in each iteration over the array, iterate through the object's properties, checking the name of the properties against the current name in the array.
If found, then use:
modes[arr[i]]++;
If not found, then use
modes[arr[i]] = 1;
After the iterating over the array, iterate over the object's properties, checking their values, and 'remembering' the name and value of the highest one.
Working:
//Mode Calc
function mode( arr ) {
if ( !Array.isArray( arr ) ) {
throw new TypeError( 'mode()::invalid input argument. Must provide an array.' );
}
var len = arr.length,
count = {},
max = 0,
vals = [],
val;
for ( var i = 0; i < len; i++ ) {
val = arr[ i ];
if ( !count[ val ] ) {
count[ val ] = 0;
}
count[ val ] += 1;
if ( count[ val ] === max ) {
vals.push( val );
} else {
max = count[ val ];
vals = [ val ];
}
}
return vals.sort( function sort( a, b ) {
return a - b;
});
} // end FUNCTION mode()
for (i = 0; i < numberOf; i++) {
winner = ( mode( roundWinners[i] ) );
}
Let's say I have a Javascript associative array (a.k.a. hash, a.k.a. dictionary):
var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;
How can I iterate over the keys in sorted order? If it helps simplify things, I don't even need the values (they're all just the number 1).
You can use the Object.keys built-in method:
var sorted_keys = Object.keys(a).sort()
(Note: this does not work in very old browsers not supporting EcmaScript5, notably IE6, 7 and 8. For detailed up-to-date statistics, see this table)
You cannot iterate over them directly, but you can find all the keys and then just sort them.
var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;
function keys(obj)
{
var keys = [];
for(var key in obj)
{
if(obj.hasOwnProperty(key))
{
keys.push(key);
}
}
return keys;
}
keys(a).sort(); // ["a", "b", "z"]
However there is no need to make the variable 'a' an array. You are really just using it as an object and should create it like this:
var a = {};
a["key"] = "value";
you could even prototype it onto object:
Object.prototype.iterateSorted = function(worker)
{
var keys = [];
for (var key in this)
{
if (this.hasOwnProperty(key))
keys.push(key);
}
keys.sort();
for (var i = 0; i < keys.length; i++)
{
worker(this[ keys[i] ]);
}
}
and the usage:
var myObj = { a:1, b:2 };
myObj.iterateSorted(function(value)
{
alert(value);
}
I agree with Swingley's answer, and I think it is an important point a lot of these more elaborate solutions are missing. If you are only concerned with the keys in the associative array and all the values are '1', then simply store the 'keys' as values in an array.
Instead of:
var a = { b:1, z:1, a:1 };
// relatively elaborate code to retrieve the keys and sort them
Use:
var a = [ 'b', 'z', 'a' ];
alert(a.sort());
The one drawback to this is that you can not determine whether a specific key is set as easily. See this answer to javascript function inArray for an answer to that problem. One issue with the solution presented is that a.hasValue('key') is going to be slightly slower than a['key']. That may or may not matter in your code.
There's no concise way to directly manipulate the "keys" of a Javascript object. It's not really designed for that. Do you have the freedom to put your data in something better than a regular object (or an Array, as your sample code suggests)?
If so, and if your question could be rephrased as "What dictionary-like object should I use if I want to iterate over the keys in sorted order?" then you might develop an object like this:
var a = {
keys : new Array(),
hash : new Object(),
set : function(key, value) {
if (typeof(this.hash[key]) == "undefined") { this.keys.push(key); }
this.hash[key] = value;
},
get : function(key) {
return this.hash[key];
},
getSortedKeys : function() {
this.keys.sort();
return this.keys;
}
};
// sample use
a.set('b',1);
a.set('z',1);
a.set('a',1);
var sortedKeys = a.getSortedKeys();
for (var i in sortedKeys) { print(sortedKeys[i]); }
If you have no control over the fact that the data is in a regular object, this utility would convert the regular object to your fully-functional dictionary:
a.importObject = function(object) {
for (var i in object) { this.set(i, object); }
};
This was a object definition (instead of a reusable constructor function) for simplicity; edit at will.
Get the keys in the first for loop, sort it, use the sorted result in the 2nd for loop.
var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;
var b = [];
for (k in a) b.push(k);
b.sort();
for (var i = 0; i < b.length; ++i) alert(b[i]);
You can use the keys function from the underscore.js library to get the keys, then the sort() array method to sort them:
var sortedKeys = _.keys(dict).sort();
The keys function in the underscore's source code:
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
};
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
<script type="text/javascript">
var a = {
b:1,
z:1,
a:1
}; // your JS Object
var keys = [];
for (key in a) {
keys.push(key);
}
keys.sort();
var i = 0;
var keyslen = keys.length;
var str = '';
//SORTED KEY ITERATION
while (i < keyslen) {
str += keys[i] + '=>' + a[keys[i]] + '\n';
++i;
}
alert(str);
/*RESULT:
a=>1
b=>1
z=>1
*/
</script>
var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;
var keys=Object.keys(a).sort();
for(var i=0,key=keys[0];i<keys.length;key=keys[++i]){
document.write(key+' : '+a[key]+'<br>');
}
I really like #luke-schafer's prototype idea, but also hear what he is saying about the issues with prototypes. What about using a simple function?
function sortKeysAndDo( obj, worker ) {
var keys = Object.keys(obj);
keys.sort();
for (var i = 0; i < keys.length; i++) {
worker(keys[i], obj[keys[i]]);
}
}
function show( key, value ) {
document.write( key + ' : ' + value +'<br>' );
}
var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;
sortKeysAndDo( a, show);
var my_object = { 'c': 3, 'a': 1, 'b': 2 };
sortKeysAndDo( my_object, show);
This seems to eliminate the issues with prototypes and still provide a sorted iterator for objects. I am not really a JavaScript guru, though, so I'd love to know if this solution has hidden flaws I missed.
I want to define what I understand is an associative array (or maybe an object) such that I have entries like the following:
"Bath" = [1,2,5,5,13,21]
"London" = [4,7,13,25]
I've tried the following:
var xref = new Object;
xref = [];
obj3 = {
offices: []
};
xref.push(obj3);
Then cycling through my data with
xref[name].offices.push(number);
But I get "TypeError: xref[name] is undefined". What am I doing wrong ?
Use an object like you do with obj3:
var xref = {};
xref.obj3 = obj3;
var name = 'obj3';
xref[name].offices.push(number);
var obj = {
arr : [],
}
var name = "vinoth";
obj.arr.push(name);
console.log(obj.arr.length);
console.log(obj.arr[0]);
obj.prop = "Vijay";
console.log(obj.prop);
You can use an object literal.
I realised that all I really wanted was a 2 dimensional array with the first dimension being the key (ie. "BATH", "LONDON") and the second being the list of cross-references (ie. 1,2,5,5,13,21) - so I don't need to understand the Object route yet ! The other suggestions may well work and be "purer" but the 2 dimensional array is easier for my old-fashioned brain to work with.
So I did the following:
var xref = [];
// go through source arrays
for (i = 0; i < offices.length; i++) {
for (j = 0; j < offices[i].rel.length; j++) {
// Check if town already exists, if not create array, then push index
if (xref[offices[i].rel[j].town] === undefined) {
xref[offices[i].rel[j].town] = [];
alert('undefined so created '+offices[i].rel[j].town);
};
xref[offices[i].rel[j].town].push(i); // Add index to town list
};
};
I believe from reading other posts that I would have problems if any of the 'offices[i].rel[j].town' were set to undefined but the data doesn't have this possibility.
Now I can access a cross-reference list by doing something like:
townlist = "";
for (i = 0; i < xref["BATH"].length; i++) {
townlist += offices[xref["BATH"][i]].name+' ';
};
alert(townlist);
When I try to convert the array below to a string using JSON.stringify, I get to see empty square brackets only. I tried console.log to debug, but I do see the data I want to convert into a string, so what am I doing wrong here? Any help will be much appreciated!
function jsonSuccess( data ){
var jsonArr = new Array();
for( var i = 0; i < data.length; i++ ){
var shipInfo = new Array();
var shipRows = new Array();
$.each( data[i], function( key, value ){
if ( key == "EniNumber" ) {
shipInfo['E'] = value;
//console.log( shipInfo.E );
}
if ( key == "Name" ) {
shipInfo['N'] = value;
}
if ( key == "StartDate" ) {
shipInfo['S'] = value;
}
if ( key == "Rows" ) {
$.each( value, function( subKey, subValue ){
var rowContent = {
"T": subValue.T,
"X": subValue.X,
"Y": subValue.Y,
"D": subValue.D
}
shipRows.push( rowContent );
});
shipInfo['R'] = shipRows;
}
});
jsonArr[i] = shipInfo;
var myJsonString = JSON.stringify(jsonArr);
console.log(myJsonString);
}
}
You are using an Array as an object.
In Javascript you have Arrays and objects. But as you may know Arrays are also objects and this has some weird implications.
var arr = [];
arr[0] = "foo"; // this is fine
console.log(JSON.stringify(arr)); // [ "foo" ]
arr.length; // 1 ok
But since an Array is an object, we can also assign properties:
arr.foo = "bar";
console.log(arr); // [ 0: "foo", foo: "bar" ]
console.log(JSON.stringify(arr)); // [ "foo" ] .. where did bar go?
arr.length; // 1 huh?
We're mixing array values and object properties.
The JSON encoder looks at the object and sees that it's an (instanceof) Array and serializes it. It looks at arr.length (which is 1 in the example) so you get just [ "foo" ]. The properties on the array are ignored.
It's important to realize the difference between array valus and object properties. Arrays in JavaScript are never associative. If you set a property on an Array it wont increase the length and it wont show up if you loop over it in a for-loop.
Change:
var shipInfo = new Array();
To:
var shipInfo = {};
shipInfo is not an array, it is an object so try var shipInfo = {};
Demo: Problem, Solution
How can I convert something like initialArray array of JSON objects into finalObject map?
var initialArray = [
{ id:'id1', name:'name1' },
{ id:'id2', name:'name2' },
{ id:'id3', name:'name3' },
{ id:'id4', name:'name4' }
];
var finalObject = {
'id1':'name1',
'id2':'name2',
'id3':'name3',
'id4':'name4'
}
Things to consider:
IDs are strings.
I tried for in loop - couldn't make it to work - http://jsfiddle.net/5af9R/23/
Any ideas?
You need to operate on the objects in your array, not strings containing their indexes in the array.
You should also use a regular for loop to iterate over an array.
Your JSFiddle, fixed:
var x = [ {id:'1', img:'img1'}, {id:'2', img:'img2'}, {id:'3', img:'img3'} ];
var resp = {};
for( var i = 0 ; i < x.length ; i++ ){
var obj = x[i];
resp[obj.id] = obj.img;
}
document.write( JSON.stringify(resp, undefined, 2) );
DEMO
You can loop over the array, and for each object, add a new property to finalObject whose property name is the id, and whose value is the name.
var finalObject = {};
for (var i = 0, max = initialArray.length; i < max; i++)
finalObject[initialArray[i].id] = initialArray[i].name;
resp[key.id] = key.img;
You correctly call it key. But you need a value;
resp[x[key].id] = x[key].img;
var finalObject = initialArray.reduce(function(ret, obj){
ret[obj.id] = obj.name;
return ret;
}, {});
This solution is specific to the property names for the specific question, but Array.prototype.reduce is a function I use all the time for any sort of array iteration that requires a non-array result.
You're not using For In correctly jsFiddle
var x = [ {id:'1', img:'img1'}, {id:'2', img:'img2'}, {id:'3', img:'img3'} ];
var resp = {};
for( var key in x ){
resp['id' + x[key].id] = x[key].img;
}
document.write( JSON.stringify(resp, undefined, 2) );
for (var i=0; i<x.length; i++) {
var id = 'id' + x[i].id;
var img = x[i].img;
resp[id] = img;
}
if i have understood correctly you can do something like
var x =' [ {"id":"1", "img":"img1"}, {"id":"2", "img":"img2"}, {"id":"3", "img":"img3"}]';
var resp = {};
var json = $.parseJSON(x);
$(json).each(function(i,v){
resp[v.id]=v.img;
});
console.log( resp);
DEMO
you talked about json but in the fiddle you provided there was no json even jquery was not added as a resource so i made some assumptions
Today I was on the same question and I didn't find an answer here, except the answer of #adam-rackis.
The way I found is :
var initialArray = [
{ id:'id1', name:'name1' },
{ id:'id2', name:'name2' },
{ id:'id3', name:'name3' },
{ id:'id4', name:'name4' }
],
finalObject = {};
$.each(initialArray, function(k,v) {
finalObject[v.name] = v.value;
});