Sort array by key in JavaScript - javascript

I've created an array in JavaScript and inserted objects with keys of object_ids:
var ar = [];
ar[4] = 'a';
ar[2] = 'b';
ar[8] = 'c';
ar[5] = 'd';
Problem is when I print this out the array I get is:
[undefined, undefined, "b", undefined, "a", "d", undefined, undefined, "c"]
and
ar.length = 9
How do I prevent the array from auto filling with undefined values and simply save this array as a 4-element array?
Iteration over an array is not what I expect here.
Thanks!

You can use an object literal instead of an array
var ar = {};
ar[4] = 'a';
ar[2] = 'b';
ar[8] = 'c';
ar[5] = 'd';
// {"2":"b","4":"a","5":"d","8":"c"}
You can iterate like this:
for (var i in a) {
console.log(a[i]);
}

Here's what you are doing:
var ar = [];
ar[8] = 'c'; // creates [undefined, undefined, undefined, undefined, undefined, undefined, undefined, 'c'];
I believe this is what you want:
var ar = {};
ar[4] = 'a';
ar[2] = 'b';
ar[8] = 'c';
ar[5] = 'd';
Object.keys(ar).length == 4; // true
More information on Object.keys

I think you are confusing the behavior of JavaScript Arrays with the associative-array behavior of all JavaScript objects. Try this instead:
var a = {};
a[4] = 'a';
a[2] = 'b';
a[8] = 'c';
a[5] = 'd';
a; // {'2':'b', '4':'a', '8':'c', '5':'d'}
Note that the key/value pairs in an object are not ordered in any way. To order the keys or values you must maintain your own array of ordering.

what you want to do is probably:
array = {}
array["1"] = "b"
array["7"] = "aaa"
now array is:
Object { 1="a", 7="b"}
is it right?

var arr = {
0 : "hello",
8 : "world",
14: "!"
};
var count = 0;
for (var k in arr) {
++count;
}
document.write(arr[0] + " " + arr[8] + arr[14] + " with a length of " + count );
Outputs hello world! with a length of 3
You can use an Object.. and here is how to collect the count (if you needed)
Fiddle

There is no guarantee that iterating an Object using the for...in statement be in any specific order. The behavior is undefined in ECMA Script specification, quote:
The mechanics of enumerating the properties ... is implementation dependent.
Chrome doesn't iterate elements in order in many cases, last time I checked Opera went the same way and just now I read here that IE9 has adopted the same behavior. So your only solution that is guaranteed to keep both the association and order of elements is to use an Object to store keys and values and an Array to store the order:
var obj = { 4: 'a', 2: 'b', 8: 'c', 5: 'd' };
var order = [ 4, 2, 8, 5 ];
for( var i in order ) {
//do something with obj[ order[i] ]
}

Related

Property of an Object in an Array

i have an array with objects as elements:
var array = [{a:x}, {b:y}, {a:z}]
now i want to add for array[0] and array[2] an extra property
array[0].b = q;
array[2].b = q;
Is it possible to call it shorter?
array[0].b = array[2].b = q
Maybe also shorter then this?
You could iterate the indices and create the property.
var array = [{ a: 'x' }, {b: 'y' }, { a: 'z' }];
[0, 2].forEach(i => array[i].b = 'q');
console.log(array);

Comparing and returning index in lodash

var x = [{a:1, b:4,c:5}, {a:1, b:2,c:7}];
var y = [{a:1, b:2,c:6}, {a:1, b:2,c:8}];
I want to compare based on first 2 key i.e a,b and get the index if it is unequal. In above example output should be fetched as 0 since b value is nt equal. How do we achieve in javascript or Lodash ? Thank you.
So you want a compare function which will compare an array of object in which you want index of an object whose two properties a and b are not equal.
Below implementation return such index(0-base) if exit else return -1.
function compare(x,y){
for(let i=0;i<x.length && i<y.length;i++){
if(x[i].a!=y[i].a || x[i].b!=y[i].b)
return i;
}
return -1;
}
var x = [{a:1, b:4,c:5}, {a:1, b:2,c:7}];
var y = [{a:1, b:2,c:6}, {a:1, b:2,c:8}];
console.log(compare(x,y)); //0
y = [{a:1, b:4,c:6}, {a:1, b:2,c:8}];
console.log(compare(x,y));//-1
y = [{a:1, b:4,c:6}, {a:1, b:3,c:8}];
console.log(compare(x,y));//1
Hope this you want.
Assuming you want to compare two objects in an array by first two keys, here's a working example. Please, feel free to elaborate.
var x = [{a:1, b:4,c:5},{a:1, b:2,c:7}];
var y = [{a:1, b:2,c:6}, {a:1, b:2,c:8}];
function customizer(obj1, obj2) {
const [a, b] = Object.keys(obj1).slice(0, 2);
return obj1[a] === obj2[a] && obj1[b] === obj2[b];
}
xIsEqual = _.isEqualWith(x[0], x[1], customizer);
yIsEqual = _.isEqualWith(y[0], y[1], customizer);
console.log(xIsEqual); // false
console.log(yIsEqual); // true
If you want to filter an array on a specific condition, you can use filter() :
y.filter(d => d.a !== d.b);
With Lodash:
_.filter(y, d => d.a !== d.b);
You can't rely on an order of object keys, 'cause iteration over object keys is implementation-dependent. It could differ from browser to browser.
Read this note.
For example, run the following code:
const obj1 = { a: 'a', 100: 'b', 2: 'c' };
console.log('object literal', Object.keys(obj1));
// at least in chrome it would be ["2", "100", "a"]
const obj2 = {};
obj2['a'] = 'a';
obj2['100'] = 'b';
obj2['2'] = 'b';
console.log('object with keys added in a specific order', Object.keys(obj2));
// same ["2", "100", "a"]

Pushing an Object to Array in js

I'm trying to push an Object to an Array using the following command:
a = a.concat(b);
a = [];
b = {a: Object1, b: Object2 ....};
So I wan to have array a to be like a = [Object1, Object2...]
But the above statement results in:
a = [[Object1, Object2...][Object11, Object12...]];
How can I achieve this in JS?
If I´m understanding what you want, you want just objects, not the keys. So, could be:
for( var key in b ){
var value = b[key];
a.push(value);
}
console.log(JSON.stringify(a));
Hope it helps...
You are concatenating two arrays with Array.concat() you need to use Array.push().
var a = [ObjectA];
var b = ObjectB;
a.push(b);
// a = [ObjectA, ObjectB];
let a = [];
let b = {a:1, b:2, c:3};
for(obj in b){
let val = {};
val[obj] = b[obj];
a.push(val);
}
console.log(a);
Did you mean something like this ?
The Object.values() method returns an array of a given object's own enumerable property values,
You could use the Object values method Object.values(), like :
Object.values(b);
Example :
var a = [];
var obj_1 = {'attr_1': 'val_1', 'attr_2': 'val_2'};
var obj_2 = {'attr_3': 'val_3', 'attr_4': 'val_4'};
var b = {'a': obj_1, 'b': obj_2};
a = Object.values(b);
console.log( a );
Hope this helps.

What does a[arr1[i]]=true do?

I am a JavaScript beginner. I have previously worked in other programming languages (C, C++ etc). What is the statement a[arr1[i]]=true; doing?
function diff(arr1, arr2) {
var newArr = [];
// Same, same; but different.
var a=[];
for(var i=0;i<arr1.length;i++)
a[arr1[i]]=true;
for(var j=0;j<arr2.length;j++)
if(a[arr2[j]])
delete a[arr2[j]];
else
a[arr2[j]]=true;
for(var k in a)
newArr.push(k);
return newArr;
}
It seems that a is a list of booleans, so that particular assignment sets one of a's indices to true. That index is computed by dereferencing arr1.
In a comment above you expressed a worry to the effect that an array is used as an index inside another array. But no need to worry about that, because it's not the array itself (viz. arr1) that's used as an index, but an element of that array (viz. arr1[i], for some i).
You're wondering about the syntax a[arr1[i]]. It's simple:
arr1[i] value is an index for array a.
If arr1[i] value is a number, 5 as an example. So it will be: a[5]=true. Nothing's special in this case.
As you said in the comment, arr1[i] might be a string, "boy" for example. Then, it will be: a["boy"]=true.
You should know that array index in JavaScript could be a string. But be careful, as W3School said, if you use a named index, JavaScript will redefine the array to a standard object. After that, all array methods and properties will produce incorrect results. For example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length; // person.length will return 0
var y = person[0]; // person[0] will return undefined
For more detail, take a look at the warning part in W3School about this.
Here's your code with comments explaining what's going on and sample output
var arr1 = [1,2,'foo','bar'];
var arr2 = [2,3,'foo'];
var diff = diff(arr1, arr2);
console.log( diff ); // ["1", "3", "bar"]
function diff(arr1, arr2) {
var newArr = [];
var a=[];
// Loop through arr1
// set the value of each entry as an index in array `a`
// set the value of the entry in `a` to true
for(var i=0;i<arr1.length;i++)
a[arr1[i]]=true;
// console.log(a); // [1: true, 2: true, foo: true, bar: true]
// Loop through arr2
// check if each entry exists as an index in array `a`
// if it does, delete the value from array `a`
// if not, set the value of the entry in `a` to true
for(var j=0;j<arr2.length;j++)
if(a[arr2[j]])
delete a[arr2[j]];
else
a[arr2[j]]=true;
// console.log(a); // [1: true, 3: true, bar: true]
// put all of the indexs of array `a` to values in `newArr`
for(var k in a)
newArr.push(k);
return newArr;
}
http://jsfiddle.net/daCrosby/6rcf1j72/
From a code-cleanup side, If you want a shorter function you could use something like one of these:
console.log( "Looping", diffLoop ); // [1, "bar", 3]
console.log( "Filtering", diffFilter ); // [1, "bar", 3]
function diffLoop(arr1, arr2){
var arr = arr1;
for(var j=0; j<arr2.length; j++)
if( arr.indexOf( arr2[j] ) > -1 )
arr.splice(arr.indexOf( arr2[j] ), 1);
else
arr.push(arr2[j]);
return arr;
}
function diffFilter(arr1, arr2){
var arr = arr1.concat(arr2);
return arr.filter(function(i) {
var in1 = arr1.indexOf(i) < 0;
var in2 = arr2.indexOf(i) < 0;
return (in1 || in2) && !(in1 && in2);
});
}
http://jsfiddle.net/daCrosby/6rcf1j72/1/
Same logic as in high level languages applies here as well.
This can easily be clarified splitting this to small blocks.
a[arr1[i]]=true;
arr1 - An array of integer
a - An array of boolean

How to sort an associative array by its values in Javascript?

I have the associative array:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
What is the most elegant way to sort (descending) by its values where the result would be an array with the respective indices in this order:
sub2, sub3, sub1, sub4, sub0
Javascript doesn't have "associative arrays" the way you're thinking of them. Instead, you simply have the ability to set object properties using array-like syntax (as in your example), plus the ability to iterate over an object's properties.
The upshot of this is that there is no guarantee as to the order in which you iterate over the properties, so there is nothing like a sort for them. Instead, you'll need to convert your object properties into a "true" array (which does guarantee order). Here's a code snippet for converting an object into an array of two-tuples (two-element arrays), sorting it as you describe, then iterating over it:
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
a = a[1];
b = b[1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < tuples.length; i++) {
var key = tuples[i][0];
var value = tuples[i][1];
// do something with key and value
}
You may find it more natural to wrap this in a function which takes a callback:
function bySortedValue(obj, callback, context) {
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0
});
var length = tuples.length;
while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
}
bySortedValue({
foo: 1,
bar: 7,
baz: 3
}, function(key, value) {
document.getElementById('res').innerHTML += `${key}: ${value}<br>`
});
<p id='res'>Result:<br/><br/><p>
Instead of correcting you on the semantics of an 'associative array', I think this is what you want:
function getSortedKeys(obj) {
var keys = Object.keys(obj);
return keys.sort(function(a,b){return obj[b]-obj[a]});
}
for really old browsers, use this instead:
function getSortedKeys(obj) {
var keys = []; for(var key in obj) keys.push(key);
return keys.sort(function(a,b){return obj[b]-obj[a]});
}
You dump in an object (like yours) and get an array of the keys - eh properties - back, sorted descending by the (numerical) value of the, eh, values of the, eh, object.
This only works if your values are numerical. Tweek the little function(a,b) in there to change the sorting mechanism to work ascending, or work for string values (for example). Left as an exercise for the reader.
Continued discussion & other solutions covered at How to sort an (associative) array by value? with the best solution (for my case) being by saml (quoted below).
Arrays can only have numeric indexes. You'd need to rewrite this as either an Object, or an Array of Objects.
var status = new Array();
status.push({name: 'BOB', val: 10});
status.push({name: 'TOM', val: 3});
status.push({name: 'ROB', val: 22});
status.push({name: 'JON', val: 7});
If you like the status.push method, you can sort it with:
status.sort(function(a,b) {
return a.val - b.val;
});
There really isn't any such thing as an "associative array" in JavaScript. What you've got there is just a plain old object. They work kind-of like associative arrays, of course, and the keys are available but there's no semantics around the order of keys.
You could turn your object into an array of objects (key/value pairs) and sort that:
function sortObj(object, sortFunc) {
var rv = [];
for (var k in object) {
if (object.hasOwnProperty(k)) rv.push({key: k, value: object[k]});
}
rv.sort(function(o1, o2) {
return sortFunc(o1.key, o2.key);
});
return rv;
}
Then you'd call that with a comparator function.
The best approach for the specific case here, in my opinion, is the one commonpike suggested. A little improvement I'd suggest that works in modern browsers is:
// aao is the "associative array" you need to "sort"
Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
This could apply easily and work great in the specific case here so you can do:
let aoo={};
aao["sub2"]=1;
aao["sub0"]=-1;
aao["sub1"]=0;
aao["sub3"]=1;
aao["sub4"]=0;
let sk=Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
Besides of this, I provide here a more "generic" function you can use to sort even in wider range of situations and that mixes the improvement I just suggested with the approaches of the answers by Ben Blank (sorting also string values) and PopeJohnPaulII (sorting by specific object field/property) and lets you decide if you want an ascendant or descendant order, here it is:
// aao := is the "associative array" you need to "sort"
// comp := is the "field" you want to compare or "" if you have no "fields" and simply need to compare values
// intVal := must be false if you need comparing non-integer values
// desc := set to true will sort keys in descendant order (default sort order is ascendant)
function sortedKeys(aao,comp="",intVal=false,desc=false){
let keys=Object.keys(aao);
if (comp!="") {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b][comp]-aao[a][comp]});
else return keys.sort(function(a,b){return aao[a][comp]-aao[a][comp]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b][comp]<aao[a][comp]?1:aao[b][comp]>aao[a][comp]?-1:0});
else return keys.sort(function(a,b){return aao[a][comp]<aao[b][comp]?1:aao[a][comp]>aao[b][comp]?-1:0});
}
} else {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b]-aao[a]});
else return keys.sort(function(a,b){return aao[a]-aao[b]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b]<aao[a]?1:aao[b]>aao[a]?-1:0});
else return keys.sort(function(a,b){return aao[a]<aao[b]?1:aao[a]>aao[b]?-1:0});
}
}
}
You can test the functionalities trying something like the following code:
let items={};
items['Edward']=21;
items['Sharpe']=37;
items['And']=45;
items['The']=-12;
items['Magnetic']=13;
items['Zeros']=37;
//equivalent to:
//let items={"Edward": 21, "Sharpe": 37, "And": 45, "The": -12, ...};
console.log("1: "+sortedKeys(items));
console.log("2: "+sortedKeys(items,"",false,true));
console.log("3: "+sortedKeys(items,"",true,false));
console.log("4: "+sortedKeys(items,"",true,true));
/* OUTPUT
1: And,Sharpe,Zeros,Edward,Magnetic,The
2: The,Magnetic,Edward,Sharpe,Zeros,And
3: The,Magnetic,Edward,Sharpe,Zeros,And
4: And,Sharpe,Zeros,Edward,Magnetic,The
*/
items={};
items['k1']={name:'Edward',value:21};
items['k2']={name:'Sharpe',value:37};
items['k3']={name:'And',value:45};
items['k4']={name:'The',value:-12};
items['k5']={name:'Magnetic',value:13};
items['k6']={name:'Zeros',value:37};
console.log("1: "+sortedKeys(items,"name"));
console.log("2: "+sortedKeys(items,"name",false,true));
/* OUTPUT
1: k6,k4,k2,k5,k1,k3
2: k3,k1,k5,k2,k4,k6
*/
As I already said, you can loop over sorted keys if you need doing stuffs
let sk=sortedKeys(aoo);
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
Last, but not least, some useful references to Object.keys and Array.sort
Here is a variation of ben blank's answer, if you don't like tuples.
This saves you a few characters.
var keys = [];
for (var key in sortme) {
keys.push(key);
}
keys.sort(function(k0, k1) {
var a = sortme[k0];
var b = sortme[k1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var value = sortme[key];
// Do something with key and value.
}
No unnecessary complication required...
function sortMapByValue(map)
{
var tupleArray = [];
for (var key in map) tupleArray.push([key, map[key]]);
tupleArray.sort(function (a, b) { return a[1] - b[1] });
return tupleArray;
}
i use $.each of jquery but you can make it with a for loop, an improvement is this:
//.ArraySort(array)
/* Sort an array
*/
ArraySort = function(array, sortFunc){
var tmp = [];
var aSorted=[];
var oSorted={};
for (var k in array) {
if (array.hasOwnProperty(k))
tmp.push({key: k, value: array[k]});
}
tmp.sort(function(o1, o2) {
return sortFunc(o1.value, o2.value);
});
if(Object.prototype.toString.call(array) === '[object Array]'){
$.each(tmp, function(index, value){
aSorted.push(value.value);
});
return aSorted;
}
if(Object.prototype.toString.call(array) === '[object Object]'){
$.each(tmp, function(index, value){
oSorted[value.key]=value.value;
});
return oSorted;
}
};
So now you can do
console.log("ArraySort");
var arr1 = [4,3,6,1,2,8,5,9,9];
var arr2 = {'a':4, 'b':3, 'c':6, 'd':1, 'e':2, 'f':8, 'g':5, 'h':9};
var arr3 = {a: 'green', b: 'brown', c: 'blue', d: 'red'};
var result1 = ArraySort(arr1, function(a,b){return a-b});
var result2 = ArraySort(arr2, function(a,b){return a-b});
var result3 = ArraySort(arr3, function(a,b){return a>b});
console.log(result1);
console.log(result2);
console.log(result3);
Just so it's out there and someone is looking for tuple based sorts.
This will compare the first element of the object in array, than the second element and so on. i.e in the example below, it will compare first by "a", then by "b" and so on.
let arr = [
{a:1, b:2, c:3},
{a:3, b:5, c:1},
{a:2, b:3, c:9},
{a:2, b:5, c:9},
{a:2, b:3, c:10}
]
function getSortedScore(obj) {
var keys = [];
for(var key in obj[0]) keys.push(key);
return obj.sort(function(a,b){
for (var i in keys) {
let k = keys[i];
if (a[k]-b[k] > 0) return -1;
else if (a[k]-b[k] < 0) return 1;
else continue;
};
});
}
console.log(getSortedScore(arr))
OUPUTS
[ { a: 3, b: 5, c: 1 },
{ a: 2, b: 5, c: 9 },
{ a: 2, b: 3, c: 10 },
{ a: 2, b: 3, c: 9 },
{ a: 1, b: 2, c: 3 } ]
A modern approuch to this:
Object.fromEntries(Object.entries(data).sort((a,b)=>b[1]-a[1]).slice(0,5))
P.S: I did an optional slice, you can remove it if you want.
#commonpike's answer is "the right one", but as he goes on to comment...
most browsers nowadays just support Object.keys()
Yeah.. Object.keys() is WAY better.
But what's even better? Duh, it's it in coffeescript!
sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b]
sortedKeys
'a' : 1
'b' : 3
'c' : 4
'd' : -1
[ 'd', 'a', 'b', 'c' ]

Categories