After creating a multi-dim array like this, how do I sort it?
Assuming 'markers' is already defined:
var location = [];
for (var i = 0; i < markers.length; i++) {
location[i] = {};
location[i]["distance"] = "5";
location[i]["name"] = "foo";
location[i]["detail"] = "something";
}
For the above example, I need to sort it by 'distance'.
I've seen other questions on sorting arrays and multi-dim arrays, but none seem to work for this.
location.sort(function(a,b) {
// assuming distance is always a valid integer
return parseInt(a.distance,10) - parseInt(b.distance,10);
});
javascript's array.sort method has an optional parameter, which is a function reference for a custom compare. the return values are >0 meaning b first, 0 meaning a and b are equal, and <0 meaning a first.
Have you tried this?
location.sort(function(a,b) {
return a.distance - b.distance;
});
Both sort functions posted so far should work, but your main problem is going to be using location as a variable as it is already system defined.
Related
Please check the code below -
custom_array.push(...) is working
but
custom_array[i] = "n"
is not working.
There are a couple more things which i am not sure why it is not working. Please note the comments with "?" which is not working. Please refer fiddle - http://jsfiddle.net/vc0bbm3d/
The reason that setting items using bracket syntax doesn't work for your object inheriting an array, is that it's not actually an array.
An array has special code for handling property assignment (which is what you do with the bracket syntax) when the property name is an integer. If the index is outside the current length, the length property is adjusted.
When you assign a value to a property in your object, there is no special code to handle the length. The property is just assigned as usual, and the length is never adjusted. As the object already has code for handling what's happening when you use the bracket syntax, the array that it inherts never comes into play.
For the bracket syntax to work in that way, the object has to be an actual array.
try
ar[3] = 2;
ar.length =4
That way it knows you have added something.
Here's an example of what I mean when I say create a layer around the default array object to extend functionality:
var SuperArray = function(){
this.arr = Array.prototype.slice.call(arguments);
};
//abstraction of default array functionality
SuperArray.prototype.set = function(index, value){
this.arr[index] = value;
return this;
};
SuperArray.prototype.unset = function(index){
this.arr.splice(index, 1);
return this;
};
//extension of default array functionality
SuperArray.prototype.consoleList = function(){
var arr = this.arr;
for(var i = 0, l = arr.length; i < l; i++){
console.log(arr[i]);
};
return this;
};
var extArr = new SuperArray(1,2,3);
extArr.set(2, 25); //does array[2] = 25;
extArr.unset(1); //removes array[1]
extArr.consoleList();//console.logs all items in array
extArr.set(2, 25).unset(1).consoleList();//same thing
this simple object accepts arguments and sets them directly into an array, which we then manipulate how we wish. You can then add any utility functions that you need, check for existing array functionality, etc.
You know that in Javascript you can access the length of an text/array with length property:
var obj = ["Robert", "Smith", "John", "Mary", "Susan"];
// obj.length returns 5;
I want to know how this is implemented. Does Javascript calculates the length property when it is called? Or it is just a static property which is changed whenever the array is changed. My question is asked due to the following confusion in best-practices with javascript:
for(var i = 0; i < obj.length; i++)
{
}
My Problem: If it is a static property, then accessing the length property in each iteration is nothing to be concerned, but if it is calculated on each iteration, then it cost some memory.
I have read the following definition given by ECMAScript but it doesn't give any clue on how it is implemented. I'm afraid it might give a whole instance of array with the length property calculated in run-time, that if turns out to be true, then the above for() is dangerous to memory and instead the following should be used:
var count = obj.length;
for(var i = 0; i < count; i++)
{
}
Array in JavaScript is not a real Array type but it's an real Object type.
[].length is not being recalculated every time, it is being operated by ++ or -- operators.
See below example which is behaving same like array.length property.
var ArrayLike = {
length: 0,
push: function(val){
this[this.length] = val;
this.length++;
},
pop: function(){
delete this[this.length-1];
this.length--;
},
display: function(){
for(var i = 0; i < this.length; i++){
console.log(this[i]);
}
}
}
// output
ArrayLike.length // length == 0
ArrayLike.push('value1') // length == 1
ArrayLike.push('value2') // length == 2
ArrayLike.push('value3') // length == 3
ArrayLike.pop() // length == 2
ArrayLike.length === 2 // true
var a = ["abc","def"];
a["pqr"] = "hello";
What is a.length?
2
Why?
a.length is updated only when the index of the array is a numeric value. When you write
var a = ["abc","def"];
It is internally stored as:
a["0"] = "abc"
a["1"] = "def"
Note that the indexes are really keys which are strings.
Few more examples:
1.)
var a = ["abc","def"];
a["1001"] = "hello";
What is a.length?
1002
2.) Okay, let's try again:
var a = ["abc","def"];
a[1001] = "hello";
What is a.length?
1002
Note here, internally array is stored as
a["0"] = "abc"
a["1"] = "def"
a["1001"] = "hello"
3.) Okay, last one:
var a = ["abc"];
a["0"] = "hello";
What is a[0]?
"hello"
What is a.length?
1
It's good to know what a.length actually means: Well now you know: a.length is one more than the last numerical key present in the array.
I want to know how this is implemented. Does Javascript calculates the length property when it is called? Or it is just a static property which is changed whenever the array is changed.
Actually, your question cannot be answered in general because all the ECMA specs say is this:
The length property of this Array object is a data property whose
value is always numerically greater than the name of every deletable
property whose name is an array index.
In other words, the specs define the invariant condition of the length property, but not it's implementation. This means that different JavaScript engines could, in principle, implement different behavior.
Folks,
Not sure if eval() or window() is the answer, but I am trying to loop through an array, and create variables for each item in that array dynamically.
My myArray looks like:
['foo','bar','baz']
code:
for (var i = myArray.length - 1; i >= 0; i--) {
var myVar = eval(myArray[i])
};
console.log(foo)
console.log(bar)
console.log(baz)
Is this possible?
I think you could do it by creating parameters in an object maybe?
var myObject = {};
for(var i=0;i<myArray.length;i++) {
myObject[ myArray[i] ];
}
If you don't set them to anything, you'll just have an object with some parameters that are undefined. I'd have to write this myself to be sure though.
You cannot create different "variable names" but you can create different object properties. There are many ways to do whatever it is you're actually trying to accomplish. In your case I would just do
for (var i = myArray.length - 1; i >= 0; i--) {
console.log(eval(myArray[i]));
};
More generally you can create object properties dynamically, which is the type of flexibility you're thinking of.
var result = {};
for (var i = myArray.length - 1; i >= 0; i--) {
result[myArray[i]] = eval(myArray[i]);
};
I'm being a little handwavey since I don't actually understand language theory, but in pure Javascript (including Node) references (i.e. variable names) are happening at a higher level than at runtime. More like at the call stack; you certainly can't manufacture them in your code like you produce objects or arrays. Browsers do actually let you do this anyway though it's terrible practice, via
window['myVarName'] = 'namingCollisionsAreFun';
(per comment)
I was pondering something earlier. I wanted to check if a function had already been put into an array. If so throw an exception. I did this little test with the console...
So I guess I could say that the objects are always just references, and after setting a as x I could change x and a would be effected as well?
Would this mean that the condition x = a no matter what, which is what I want.
Using this to check if the function/object is already in the array I could just do this correct...
Is there a better way to do this?
Would this also mean that if I pass a variable to a function and mutate it in that function it will be mutated outside of that function as well?
EDIT
I guess I am right about the mutation with this little test. But I don't get why its bar in the first log in the second example
EDIT END
Example 1:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
console.log(x == a); //comes out false
//Set a as x
a = x;
console.log(x == a); //comes out true
Example 2:
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) != -1;
};
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
var z = a;
console.log(x == a); //comes out false
var l = [];
l.push(x);
//Set a as x
a = x;
l.push(a);
console.log(x == a); //comes out true
console.log(l.Contains(x)); //Should come out true
console.log(l.Contains(a)); //Should come out true
console.log(l.Contains(z)); //Should come out false
Your question isn't entirely clear to me but I'll try to answer as best I can.
Improving the function
Your function could be simplified to leverage the indexOf function.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) >= 0;
};
Also I want to point out that in your implementation you're looping through everything when you could exit early by returning inside the if.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
var i;
for (i = 0; i < this.length; i += 1) {
if (this[i] === obj) {
return true;
}
}
return false;
};
x == a
I think you understand but just want to clarify, x and a are different originally because they are referencing different functions. When you set x = a they are both pointing at the function declared originally in x and are therefore the same. Even thought the functions are identical in terms of implementation, they were both constructed and then placed in different parts of memory.
When you do this:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")}
x and a point to different functions. Even if you compare them for equality, they are not equal as all equality checking does here is see if they point to the same function or not - there is no attempt made to see if they would produce the same output when run or not (that is almost impossible to do in general, after all).
When you do something like x = a, x now references whatever a is referencing - the same object. So now they compare equal.
If you need to see if a function already exists in an array, I suggest instead of just placing arrays in a big list, you create a dictionary (hashmap, hashtable, whatever you want to call it) that uses strings as keys as function as values. The key would be the 'name' of a function - whenever you make that function you'd use the same name, and names in different places in memory but with the same characters in them WILL compare equal.
You're really confused. Everything in JavaScript (except for primitive data types, null and undefined) is an object, and objects are stored in variables as reference. Read the following answer to know more about the differences between the two: https://stackoverflow.com/a/13268731/783743
When you define two identical functions (in your case x and a) JavaScript sees them as separate functions. This is because in addition to the function body a function also maintains its own environment and state. Hence x and a are not the same function which is why x === a returns false.
By setting x = a you're essentially copying the reference stored in a into x. Hence they now point to the same function (which is the function a was originally referring to). The function x was originally referring to is now lost and will eventually be garbage collected. Thus x === a now returns true.
BTW you don't need to create a special Contains function to check whether an object is already inside an array. Just use indexOf:
var array = [];
function x() {}
array.indexOf(x); // returns -1
array.push(x);
array.indexOf(x); // returns 0
If the index is less than 0 the object is not in the array.
If you want to check whether the function body of two functions is the same then use this function:
function sameFunctionBody(a, b) {
return String(a) === String(b);
}
Now console.log(sameFunctionBody(x, a)) will return true as long as both the functions are exactly the same (including whitespace, parameters, function name, etc).
This is so simple I am baffled. I have the following:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
for (t in stypes) {
if (stypes[t] != x) {
alert(stypes[t]);
}
}
Once the values have iterated it starts returning a dozen functions like
function (iterator, context) {
var index = 0;
iterator = iterator.bind(context);
try {
this._each(function (value) {iterator(value, index++);});
} catch (e) {
if (e != $break) {
throw e;
}
}
return this;
}
What the heck is going on?
Edit: In these scripts I am using http://script.aculo.us/prototype.js and http://script.aculo.us/scriptaculous.js I remember now reading about the way prototype extends arrays and I am betting this is part of it. How do I deal with it?
The for enumeration is going to go over every member of the object you passed it. In this case an array, which happens to have functions as members as well as the elements passed.
You could re-write your for loop to check if typeof stypes[t] == "function" or yada yada. But IMO you are better off just modifying your looping to only elements..
for(var i = 0, t; t = stypes[i]; ++i){
if (t != x) {
alert(t);
}
}
Or
for(var i = 0; i < stypes.length; ++i){
if (stypes[i] != x) {
alert(stypes[i]);
}
}
I wanted to migrate my last comment up to the answer to add the notice of the a caveat for the first type of loop.
from Simon Willison's "A re-introduction to JavaScript"..
for (var i = 0, item; item = a[i]; i++) {
// Do something with item
}
Here we are setting up two variables.
The assignment in the middle part of
the for loop is also tested for
truthfulness - if it succeeds, the
loop continues. Since i is incremented
each time, items from the array will
be assigned to item in sequential
order. The loop stops when a "falsy"
item is found (such as undefined).
Note that this trick should only be
used for arrays which you know do not
contain "falsy" values (arrays of
objects or DOM nodes for example). If
you are iterating over numeric data
that might include a 0 or string data
that might include the empty string
you should use the i, j idiom instead.
you want to do:
for (var i in object) {
if (!object.hasOwnProperty(i))
continue;
... do stuff ...
}
As for..in enumeration iterates over all properties (enumerable or otherwise) that exist on both the object and its prototype chain. The hasOwnProperty check restricts iteration to just those properties on the actual object you want to enumerate.
ES5 makes things a little better for library developers (and help avoid this stuff) but we won't see that ina shipping browser for quite a while :-(
[edit: replacing return with continue. lalalalala ;) ]
Since prototype has extended the array for your convenience you should take advantage of it. Your example could be rewritten as:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
stypes.without(x).each(alert);
It should be
for (t in stypes) {
if (t != x) {
alert(t);
}
}