This question already has answers here:
Elements order in a "for (… in …)" loop
(10 answers)
Closed 9 years ago.
I have an associative array (object) in wich I store data loaded from a 3rd party.
// 3rdPartyData is also an associative array
for(var key in 3rdPartyData) {
cookie[key] = 3rdPartyData[key];
}
My object gets stored into a cookie at the end and gets loaded form a cookie before (or created {} if no cookie exists).
Each page view the data from the 3rd party gets added or updated in my cookie array.
Question: If I wore to look the cookie, would the loop always get each key in the order they wore added to it or would the order be changed?
If so can anyone provide an idea on how to manage something like this?
The order of keys in for(var key in some_object) can be any, and certainly is not always sorted, but you can force the order to be the one you want:
for(var key in Object.keys(3rdPartyData).sort(keysSorter) {
cookie[key] = 3rdPartyData[key];
}
keysSorter = function(a, b) {
if (a === b) { // Should not actually be the case when sorting object keys
return 0;
}
// Compare a and b somehow and return 1 or -1 accordingly
return a < b ? 1 : -1;
}
And to make sure Object.keys() will work:
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};
Related
This question already has answers here:
javascript sorting array based on another array
(1 answer)
Sort an array in the same order of another array
(4 answers)
Closed 3 years ago.
I have a criticality array and I want to sort by criticality, something like this:
let criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'];
I get this order randomly, sometimes ** CRITICALITY_LOW ** comes in position 1 of the matrix ie either position 2, or 'CRITICALITY_MEDIUM' in 0 position,
What I want to do is order in the following order, regardless of the order that comes to me, sometimes I have just one criticality, or two:
['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
I tried to use sort function to order what I've done so far is this:
return criticalityTypes.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
});
But without success, any help?
You could take an object with the wanted order and sort by the delta of the values.
var criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'],
order = { CRITICALITY_HIGH: 1, CRITICALITY_MEDIUM: 2, CRITICALITY_LOW: 3 };
criticalityTypes.sort((a, b) => order[a] - order[b]);
console.log(criticalityTypes);
Just another way:
let criticalityTypes = ['CRITICALITY_LOW', 'CRITICALITY_HIGH', 'CRITICALITY_MEDIUM'];
let orderedItems = [];
let desiredOrder = ['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
for (var i = 0; i < desiredOrder.length; i++) {
if (criticalityTypes.indexOf(desiredOrder[i]) > -1) {
orderedItems.push(desiredOrder[i]);
}
}
console.log(orderedItems);
The problem here is that you as the consumer of the api, do not have any clue what an "order" means for this items, as they are not "quantized", they are ideas, not an integer that you could call 'order' so you know what is what, the string is just for the display anyway.
Since you can not change the api, BUT they are always only these 3 and you always want them in the same order, you can mock your current call, put this as a 'placeholder' comparer so that you mock the calls to this function, until someones gives you something that you can use numericaly to determine an order, 'ascending' or 'descending' requires something quantized to have a meaning.
function criticalityTypes(a,b){
return ['CRITICALITY_HIGH', 'CRITICALITY_MEDIUM', 'CRITICALITY_LOW'];
}
This question already has answers here:
Sort an array of objects by dynamically provided list of object properties in a order by then by style
(5 answers)
Closed 3 years ago.
I have two arrays. One array is the array of items needing to be sorted. Another array is the keys (properties of that object) to sort by. I am wanting to have a function that sorts the array by each key given.
I have tried to loop over the keys array and pop each key off of the array and then sort but adding that key to the ternary I am using to sort the array has been giving me issues.
export function sortOrdersByKeys<T>(ordersArr: T[], sortByKeys: string[]): T[]
{
if (sortByKeys.length === 0) {
return ordersArr;
} else {
const lastItem = sortByKeys.pop();
return sortWithKey(ordersArr, lastItem);
}
}
function sortWithKey(arr, key) {
key = key[0];
for (let i = 0; i < key.length(); i++) {
}
return arr.sort((a, b) => (a.key > b.key) ? 1 : -1);
}
This is a recursive function to sort based in the keys array. let me know if you need an explanation.
function sortWithKey(arr, keys) {
const KEY = keys.pop();
arr = arr.sort((a, b) => (a[KEY]> b[KEY]) ? 1 : -1);
if(keys.legth <=0){
return arr;
}
return sortWithKey(arr, keys) ;
}
There are a few things going wrong here:
1) a.key will look up the "key" property of that object. You probably want a[key]
2) .length() is probably not a function
3) there is neither a recursive call nor a loop in your sortOrderByKeys
4) What is key = key[0]; supposed to do? To take only the first character of the key?
Your overall algorithm will also not work.
array.sort(a).sort(b)
... will sort the array first on a and then on b. So it actually yields the same result as array.sort(b) ...
You rather have to sort once, and then when comparing two array elements a and b, then go over the keys until you find a difference.
This question already has answers here:
Fast stable sorting algorithm implementation in javascript
(16 answers)
Closed 6 years ago.
Here is my jsFiddle:
//Change this variable to change the number of players sorted
var numberOfPlayers = 15;
var teams = [];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(var a=0; a<numberOfPlayers; a++){
updateStandings();
teams.push(new Team(alphabet.charAt(a)));
}
console.log("Teams:");
for(var x=0; x<teams.length; x++){
console.log(teams[x].name);
}
//Functions and such
function updateStandings(){
teams.sort(function(a, b) {
if(a.score == b.score){
if(a.tiebreak == b.tiebreak){
return teams.indexOf(a)-teams.indexOf(b);
}else{
return b.tiebreak-a.tiebreak;
}
}else{
return b.score-a.score;
}
});
}
function Team(name){
this.name = name;
this.score = 0;
this.tiebreak = 0;
}
I assumed the problem was that javascript sorting was unstable, and changed my compare function, but it still does not work.
The generic approach to stable sorting in JS is as follows:
function stable_sort(array, sortfunc) {
function _sortfunc(a, b) { return sortfunc(array[a], array[b]) || a - b; }
return array.map((e, i) => i) . sort(_sortfunc) . map(i => array[i]);
}
What this actually does is to sort a list of indices. Then it maps the sorted list of indices back to the original array. The sort function is rewritten to compare the values in the array at those indices, and if they are equal then fall back to a comparison of indices themselves.
This approach avoids the problem in your code which is that it is doing indexOf look-ups into an array which is the middle of being sorted.
This question could be informative.
According to the documentation, sort method is not required to be stable: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort In some browsers it is stable, in some not.
You do need to change the compare function, but not in the way that you tried. The reason is that you compare
return teams.indexOf(a)-teams.indexOf(b);
in the current array. It means that if the order of a and b has changed on the previous steps, your sorting routine will preserve this new order, not the one that these elements had in the beginning.
There are different ways to solve it. For example, you can create a copy of the array before sorting and execute indexOf on this copy. It will preserve the order that elements had had before sorting started.
But if your know that order in advance, you can also use this knowledge. For example, if before sorting the teams was sorted by their names, you can compare names as strings instead of positions in the array, it would be much more efficient than the first option.
Because JS' sorting is typically unstable. From §22.1.3.24 of the spec:
The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).
Your teams are created with identical properties except their name, so the line actually performing the sort is:
return teams.indexOf(a)-teams.indexOf(b);
Because you're calling indexOf, it searches for the item (and its index) each repetition of the sort. Sorting mutates the array (from MDN: it "sorts the elements of an array in place and returns the array").
You are searching for the item within the same array you are sorting, so the index may change on each iteration. Done correctly (relatively speaking), you could produce a never-ending sort with that.
For example:
const data = [1, 3, 2, 4];
let reps = 0;
data.sort((a, b) => {
console.log(data);
const ia = data.indexOf(a), ib = data.indexOf(b);
if (ia === ib || reps > 50) {
return 0;
} else if (ia < ib) {
return 1;
} else if (ib < ia) {
return -1;
}
});
This question already has answers here:
How do I enumerate the properties of a JavaScript object? [duplicate]
(14 answers)
Closed 8 years ago.
In Javascript, I'd like to have an object with three properties, "zone1", "zone2", "zone3", each of which store an array of place names. I would like to search for a match by iterating through the arrays to find a place name.
The following questions almost gets me there, but don't work for me because I am not using jQuery, and I want the value, not the key:
Performing a foreach over an associative array of associative arrays
Getting a list of associative array keys
My code looks like this:
var zoneArray = {};
zoneArray["zone1"] = ["placeA", "placeB"];
zoneArray["zone2"] = ["placeC", "placeD"];
function getZone(place, zoneArray) {
var zone;
for (var key in zoneArray) {
for(i = 0; i<key.length; i++) {
if(key[i] == place) {
zone = key;
return zone;
}
}
}
}
getZone("placeC", climateZoneArray);
Apparently however, "key[i]" is referring to letters of the zone names, like, "z" "o" "n" "e"
Could anybody please help me understand or best handle this situation in Javascript?
Use zoneArray[key] to access the array.
for (var key in zoneArray) {
var arr = zoneArray[key]
for(i = 0; i<arr.length; i++) {
if(arr[i] == place) {
zone = key;
return zone;
}
}
}
Using for ... in to iterate over an object's properties can lead to some pretty surprising results, especially if you're working in an environment where Object.prototype has been extended. This is because for ... in will iterate over an objects enumerable properties and the enumerable properties contained in that objects prototype chain. If this isn't what you want but you are going to use for ... in anyways, it's recommended to have a conditional statement at the top of the loop that checks that the property belongs to the object which is being iterated over. (if (!foo.hasOwnProperty(x)) continue;). Luckily, there is Object.keys(). You can use Object.keys() to get an array of an objects own enumerable properties, if you do this you can skip hasOwnProperty ugliness. Instead of iterating over the object you can iterate over an array of it's keys.
var collection = {
zone1: ['placeA', 'placeB'],
zone2: ['placeC', 'placeD']
};
function getZone(needle, collection) {
var zones = Object.keys(collection),
found;
for (var i = 0, l = zones.length; i < l; i++) {
found = collection[zones[i]].filter(function(place) {
return needle == place;
});
if (found.length > 0) {
return zones[i];
}
}
};
console.log(getZone('placeC', collection));
This is also here on jsfiddle.net
One last thing, be very careful when creating variables, in the inner for loop you created the variable i without using the var keyword. This resulted in i being bound to the global context, something you really want to avoid.
This question already has answers here:
Elements order in a "for (… in …)" loop
(10 answers)
Closed 8 years ago.
i need to get real order of simple javascript abject, but i get incorrect answer from this code:
var Obj={"x":"z", "2":"a", "1":"b"};
for(i in Obj)
document.write(Obj[i]+"<br>");
I expect to see z, a, b as answer, but i get b, a, z
See the code in action:
http://jsfiddle.net/gpP7m/
There's no guaranteed order in object keys iteration.
A for...in loop iterates over the properties of an object in an
arbitrary order
If you need one, use an array of key/value elements :
var obj=[
{key:"x", value:"z"},
{key:"2", value:"a"}
];
for (var i=0; i<obj.length; i++) document.write(obj[i].value+'<br>');
On a modern browser (not IE8), you can do :
document.write(obj.map(function(kv){ return kv.value }).join('<br>'));
(which doesn't do exactly the same but probably does what you want)
Check for below sample too
var data1 = {"x":"z", "2":"a", "1":"b"};
var arr = [];
var i=0;
$.each(data1,function(index,value) {
arr[i++] = value;
});
var len = arr.length-1;
while( len>=0 ) {
if( arr[len] !== undefined ) {
alert(arr[len]);
}
len--;
}
and referece link is Reverse object in jQuery.each
And fiddle update http://jsfiddle.net/gpP7m/3/