Sort with custom function giving reversed results - javascript

I have the following array (here shown as JSON):
[{
"value": -1,
"absolute": false,
"callTime": 0
}, {
"value": 23,
"absolute": true,
"callTime": 1365179295887
}, {
"value": 1,
"absolute": false,
"callTime": 0
}, {
"value": 1,
"absolute": true,
"callTime": 0
}]
I need to sort this array by putting the objects with the highest values of the callTime property at the top of the array.
I use the following code (based on the explanation of the subject offered by MDN):
var handlers = JSON.parse("[...]");
handlers.sort(function(firstHandler, secondHandler) {
if (firstHandler.callTime < secondHandler.callTime) {
return -1; // sort firstHandler to a lower index than secondHandler.
} else {
return 1; // sort secondHandler to a lower index than firstHandler.
}
return 0;
});
console.log(JSON.stringify(handlers));
After running the function, I get the following output:
[{
"value": 1,
"absolute": true,
"callTime": 0
}, {
"value": 1,
"absolute": false,
"callTime": 0
}, {
"value": -1,
"absolute": false,
"callTime": 0
}, {
"value": 94,
"absolute": true,
"callTime": 1365179553381
}]
Which seems to be the inverse of what I'm expecting (notice how the only object with callTime different than zero is at the bottom).
I think there I might be missing something big here, or maybe I'm just misled, but also changing the body of the function to:
return firstHandler.callTime - secondHandler.callTime
should give the correct results, yet it doesn't seem to.
What could I be doing wrong?

Your sort function is incorrect. The logic is reversed, because your sort function is indicating that elements with smaller values of callTime come first, whereas you want larger values to be at the top of the array. Also, you always return -1 or 1, and never 0. It should return 0 when the elements are tied.
Rewrite it as follows:
handlers.sort(function(firstHandler, secondHandler) {
if (firstHandler.callTime > secondHandler.callTime) {
return -1; // sort firstHandler to a LOWER index than secondHandler.
} else if (firstHandler.callTime < secondHandler.callTime) {
return 1; // sort secondHandler to a LOWER index than firstHandler.
}
return 0; // sort firstHandler and secondHandler as equal
});

Related

Is there any way to display 0 when an array is [""]?

I have an object that I'm iterating over using Object.keys(myData).map
const data = Object.keys(myData);
const output = data.map(key => (
{myData[key].bad.length} //correctly shows 2 for "bad" on "Bravo", but will show 1 for "bad" on "Charlie" when the array is[""]
));
Data
{
"Alpha": {
"bad": ["0001-00"],
"good": ["0002-00", "0003-00", "0004-00"],
"percent": 10,
"optionOne": true,
"optionTwo": false
},
"Bravo": {
"bad": ["0002-11", "0003-01"],
"good": ["0002-14", "0005-06"],
"percent": 75,
"optionOne": true,
"optionTwo": true
},
"Charlie": {
"bad": [""],
"good": ["0131-00", "0007-13", "0001-92"],
"percent": 25,
"optionOne": true,
"optionTwo": false
}
}
I have this to display how many items are in the array, but when they array is [""] it will display 1. Any suggestion on how I will be able to display 0 when there array is [""]?
I have all of my code working here: https://repl.it/repls/DapperHungryFraction
You could filter the array before taking the length.
This filters out empty strings:
myData[key].bad.filter(x=> x !== "").length;

combining replacer and fields in json.stringify

How would I use white-list of fields and a replace function at the same time when using json.stringify?
How to stringify objects through JSON's replacer function?
explains how to use a field list.
Hide null values in output from JSON.stringify()
Has an answer for filtering null values: https://stackoverflow.com/a/41116529/1497139
Based on that code snippet i am trying:
var fieldWhiteList=['','x1','x2','children'];
let x = {
'x1':0,
'x2':null,
'x3':"xyz",
'x4': null,
children: [
{ 'x1': 2, 'x3': 5},
{ 'x1': 3, 'x3': 6}
]
}
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
}
}
console.log(JSON.stringify(x, replacer,2));
And the result is:
{
"x1": 0,
"children": [
null,
null
]
}
Which is not what I expected. I would have expected the x1 values for the children to show up and not null values.
How could i achieve the expected result?
see also jsfiddle
By adding some debug output to the fiddle
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
}
console.log('ignoring '+key+'('+typeof (key)+')');
}
I got the output:
ignoring x2(string)
ignoring x3(string)
ignoring x4(string)
ignoring 0(string)
ignoring 1(string)
ignoring 2(string)
{
"x1": 0,
"children": [
null,
null,
null
]
}
which showed that potentially the keys can be array indices. In this case they are all numbers from 0 to n in string format so:
adding a regular expression to match numbers fixed the issue
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
if (key.match('[0-9]+'))
return value;
}
console.log('ignoring '+key+'('+typeof (key)+')');
}
with the expected output:
ignoring x2(string)
ignoring x4(string)
{
"x1": 0,
"x3": "xyz",
"children": [
{
"x1": 2,
"x3": 5
},
{
"x1": 3,
"x3": 6
},
{
"x1": 4,
"x3": 7
}
]
}

Get some values in json array

I have a json that looks like this.
How can I retrieve the information inside the group "demo", without looking into the array like: json['data'][0] I wanted to retrieve the info reading the first value.. "group" and if it matches demo, get all that group info.
{
"filter": "*",
"data": [
{
"group": "asdasd",
"enable": 1,
"timeout": 7,
"otpMode": 0,
"company": "cool",
"signature": "ou yeah",
"supportPage": "",
"newsLanguages": [
0,
0,
0,
0,
0,
0,
0,
0
],
"newsLanguagesTotal": 0
},
{
"group": "demo",
"enable": 1,
"timeout": 7,
"otpMode": 0,
"company": "pppppooo",
"signature": "TTCM",
"supportPage": "http://www.trz<xa",
"newsLanguages": [
0,
0
],
"newsLanguagesTotal": 0
}
]
}
So long I have:
let json = JSON.parse(body);
//console.log(json);
console.log(json['data'][1]);
Which access to "demo"
Process each "data item" and check for the group value. If it matches, then do something.
var json = JSON.parse(jsonStr);
for(var i=0;i<json.data.length;i++){
if(json.data[i].group == "demo"){
var group = json.data[i];
// Process the group info
}
}
I suggest you use the filter()
json.data.filter(function(item){
return item.group === "demo";
});
this will return the objects that have "demo" in the group property
Or if you want to get fancy es6 with it
json.data.filter(item => item.group === "demo");
If the key "group" is missing for any of the records, a simple check (similar to the code provided by #MarkSkayff) will give an error. To fix this, check to see if json["data"][i] exists and check if json["data"[i]["group"] also exists
function json_data(){
var res=[]
for (var i in json["data"]){
if(json["data"][i] && json["data"][i]["group"] === "demo"){ //strict comparison and boolean shortcircuiting
res.push(json["data"][i])
}
}
console.log(res)
}
The result is stored in res
Not enough space here but for more on boolean short circuiting read this explanation of dealing with irregular JSON data

Array Sorting in an object in javascript

I have to sort the arrays of the "Key" in ascending order and here's what I am doing .
Surprsingly the first array is getting sorted in descending order and the next two in ascending order . Whats the possible reason for this?
var MainObject4 = [{ "mainarray": [{ "Key": [9,768,78] },
{ "Key": [9,4,1] },{ "Key": [49,89,54] }]
}];
var first = MainObject4[0];
Object.keys(MainObject4[0]).forEach(function (k) {
first[k].forEach(function (j) {
Object.keys(j).forEach(function (g) {
j[g].sort();
},this);
},this);
},this);
alert(JSON.stringify(MainObject4, 0, 4));
Expected output:
[9,78,768]
[1,4,9]
[49,54,89]
Output I am getting now:
[768,78,9]
[1,4,9]
[49,54,89]
See the doc of Array.sort()
The default sort order is according to string Unicode code points.
If you want to compare numbers, you need to provide the comparison function, as said in the doc :
To compare numbers instead of strings, the compare function can simply subtract b from a.
You need to add a function to compare sort parameters:
var MainObject4 = [{
"mainarray": [{
"Key": [9, 768, 78]
}, {
"Key": [9, 4, 1]
}, {
"Key": [49, 89, 54]
}]
}];
var first = MainObject4[0];
Object.keys(MainObject4[0]).forEach(function(k) {
first[k].forEach(function(j) {
Object.keys(j).forEach(function(g) {
j[g].sort(function(a, b) {
return a - b;
});
}, this);
}, this);
}, this);
alert(JSON.stringify(MainObject4, 0, 4));
var MainObject4 = [{ "mainarray": [
{ "Key": [9,768,78] },
{ "Key": [9,4,1] },
{ "Key": [49,89,54] }
]
}];
MainObject4[0].mainarray.forEach(function (j) {
Object.keys(j).forEach(function (g) {
j[g].sort(function (a, b) {
return a - b;
});
},this);
},this);
alert(JSON.stringify(MainObject4, 0, 4));
It's happening because of JavaScript's sort method takes by default unicode to compare the elements. For sorting numbers, you have to explicitly write a call back function to compare elements. For ex
var input = [1,20,2,12];
console.log(input.sort());// prints 1,12,2,20
console.log(input.sort(function(a,b){
return a-b;
}));// prints 1,2,12,20
So, You just need to add the compare function to your sort. That's all

Firebase values are properly pulled but cannot be accessed?

I'm running into a weird issue where once I push a value to a Firebase object, two things happen:
I can't access it in the array I receive when I pull the object from Firebase.
The array I receive has no length property.
Here is what my Firebase structure looks like:
"user_solutions": {
"0":
{
"user_id": 0,
"clue_id": 0,
"hunt_id": 0,
"completed": 1
},
"1":
{
"user_id": 0,
"clue_id": 1,
"hunt_id": 0,
"completed": 0
},
"2":
{
"user_id": 0,
"clue_id": 1,
"hunt_id": 1,
"completed": 0
}
},
"-KHxBMZwVMzyiMIcbMdr":
{
clue_id: 1,
completed: 0,
hunt_id: 0,
user_id: 0
}
Here is the problematic function:
userSolutionsRef.orderByChild('user_id').startAt(0).endAt(0).once('value', (snap) => {
var solution = snap.val();
for (var i = 0; i < solution.length; i++) {
if (solution[i].hunt_id == 0) {
solutionsForThisHunt.push(solution[i]);
}
}
this.populateArray(solutionsForThisHunt);
});
When I run the debugger, solution has the value Object {0: Object, 1: Object, 2: Object, -KHxBMZwVMzyiMIcbMdr: Object}, but the length property is undefined. solutionsForThisHunt never gets populated. Also, I can access the objects individually in the debugger via snap.val()[0]/snap.val()[1]/snap.val()[2], but for some reason when I try accessing snap.val()[3] it is undefined, although it should be populated.
solution seems to be an object with keys, rather than an array. You could do the following
var solution = snap.val();
var array = Object.keys(solution).map(key => ({ ...solution[key], id: key }));
for ....

Categories