Angular 5 Sort by date, text, numbers - javascript

I have implemented reusable sorting function,sorting by number and text are working fine,But it fails for sort by date.
orderBy(array: Array<any>, fieldName: string, direction: string) {
return array.sort((a, b) => {
let objectA: number|string = '';
let objectB: number|string = '';
[objectA, objectB] = [a[fieldName], b[fieldName]];
let valueA = isNaN(+objectA) ? objectA.toString().toUpperCase() : +objectA;
let valueB = isNaN(+objectB) ? objectB.toString().toUpperCase() : +objectB;
return (valueA < valueB ? -1 : 1) * (direction == 'asc' ? 1 : -1);
});
}
how to sort by date, text numbers and special char.

try this:
orderBy(array: Array<any>, fieldName: string, direction: string) {
return array.sort((a, b) => {
let objectA: number|string|Date = '';
let objectB: number|string|Date = '';
[objectA, objectB] = [a[fieldName], b[fieldName]];
// I assume that objectA and objectB are of the same type
return typeof objectA === 'string' ? objectA.localeCompare(objectB) : objectA - objectB;
});
}
if Date type is not recognized, you may need to add es6 entry to your compilerOptions, see this answer for more details
UPDATE
If all your values to be sorted are strings try this:
orderBy(array: Array<any>, fieldName: string, direction: string) {
return array.sort((a, b) => {
let objectA: number|string|Date = '';
let objectB: number|string|Date = '';
// map function here will convert '15/12/2018' into '2018/12/15'
// so we can compare values as strings, numbers and strings
// will remain unchanged
[objectA, objectB] = [a[fieldName], b[fieldName]].map(i => i.split('/').reverse().join('/'));
return isNaN(+objectA) ? objectA.localeCompare(objectB) : +objectA - +objectB;
});
}

I think this could be best since the localCompare function returns positive for after and negatives for before and 0 for equals (in this example I'm comparing .name wich is an atribute of objects a and b that are in this.array)
this.array.sort((a, b) => {
return a.name.localeCompare(b.name);
});

if you are using type script than you can do like this , havent tried but you can tryout
public orderby(fieldName : string)
{
switch (typeof obj[fieldName].constructor.name) {
case "String":
array.sort();
case "Number":
array.sort(function(a,b){
return a-b);
});
case "Date"://you can check type and add accordingly
//as suggested by #Andriy its going to be object
array.sort(function(a,b){
return new Date(b.date) - new Date(a.date);
});
default:
throw new Error("Type of T is not a valid return type!");
}
} else {
throw new Error("Key '" + key + "' does not exist!");
}
}
for date sorting i do like this , converting values in date and get value for minus operation which returns zero, plus or negative vlaue
array.sort(function(a,b){
return new Date(b.date) - new Date(a.date);
});

Related

Simplify semver version compare logic

There's the standard npm semver version comparison library, but I have some simple logic to compare semver versions here:
const versionA = '14.8.3';
const versionB = '15.1.1';
const versionC = '15.1.2';
const semver = require('semver');
const assert = require('assert');
const isGreater = (a, b) => {
const [majorA, minorA, patchA] = String(a).split('.').map(v => Number.parseInt(v));
const [majorB, minorB, patchB] = String(b).split('.').map(v => Number.parseInt(v));
if (majorA > majorB) {
return true;
}
if (majorB > minorA) {
return false;
}
if (minorA > minorB) {
return true;
}
if (minorB > minorA) {
return false;
}
if (patchA > patchB) {
return true;
}
if (patchB > patchA) {
return false;
}
return false;
};
assert(isGreater(versionB, versionA), 'version b should be greater.');
assert(isGreater(versionA, versionB), 'version b should be greater.');
my question is - is there a way to simplify the logic in the greaterThan function? This function is supposed to replicate the logic in semver.gt().
You can use localeCompare instead, with the numeric option (with numeric, comparison is such that "1" < "2" < "10"), which is exactly the logic you're looking for:
const versionA = '14.8.3';
const versionB = '15.1.1';
const versionC = '15.1.2';
const versionD = '15.1.10';
const versionE = '15.2.1';
const versionF = '15.11.1';
const isGreater = (a, b) => {
return a.localeCompare(b, undefined, { numeric: true }) === 1;
};
// first argument version comes later than second argument:
console.log(isGreater(versionB, versionA));
console.log(isGreater(versionC, versionB));
console.log(isGreater(versionD, versionC));
console.log(isGreater(versionE, versionD));
console.log(isGreater(versionF, versionE));
console.log('---');
// second comes before first:
console.log(isGreater(versionA, versionB));
// same, return value should be false:
console.log(isGreater(versionA, versionA));
Or, equivalently, you can pass the locale string
en-US-u-kn-true
as the second parameter instead of { numeric: true }.
I believe this is logically the same and shorter, but not exactly stunning in it's simplicity
const parseInt = (v: string) : number => {
const num = Number.parseInt(v);
if(!(Number.isInteger(num) && num > 0)){
throw new Error('Could not parse positive integer from string')
}
return num;
};
const isGreater = (a: string, b: string) : boolean => {
const [majorA, minorA, patchA] = String(a).split('.').map(parseInt);
const [majorB, minorB, patchB] = String(b).split('.').map(parseInt);
if (majorA !== majorB) {
return majorA > majorB;
}
if (minorA !== minorB) {
return minorA > minorB;
}
return patchA > patchB;
};

Why is JS Map Function Returning Undefined? [duplicate]

This question already has answers here:
Why does JavaScript map function return undefined?
(13 answers)
Closed 1 year ago.
I have an array that is about 1000 in length. Why is map function returning undefined in certain indexes? Is there a way to only return array that meets this condition? I'd like to return an array with values > 0.
var total_percents = cars.map(function(element) {
var savings_percent = Number(element[0].getAttribute("percent-savings"));
if (savings_percent > 0)
return savings_percent;
});
You need to filter values after mapping, which you can do with filter array method with predicate like car => car > 0
var total_percents = cars.map((element) => Number(element[0].getAttribute("percent-savings"))).filter(car => car > 0)
You could also use reduce method for combining both operations at once:
var total_percents =
cars.reduce((acc, element) => {
const percentSavings = Number(element[0].getAttribute("percent-savings"));
if (percentSavings > 0) {
acc.push(percentSavings);
}
return acc;
}, [])
Unsure what you're attempting to accomplish, but:
Try something like this to return a sum of all pctSavings:
const totalPercents = cars.reduce((sum, el) => {
const pctSavings = +(el[0].getAttribute("percent-savings"));
if (pctSavings > 0) sum += pctSavings;
return sum;
}, 0);
To return an array of pctSavings, simply do this:
const totalPercents = cars.reduce((arr, el) => {
const pctSavings = +(el[0].getAttribute("percent-savings"));
if (pctSavings > 0) arr.push(pctSavings);
return arr;
}, []);
To get the max pctSavings do this:
let maxPctSavings = 0;
cars.forEach(el => {
const pctSavings = +(el[0].getAttribute("percent-savings"));
if (pctSavings > maxPctSavings) maxPctSavings = pctSavings
});
console.log(maxPctSavings) // this is your answer
Using reduce to both filter and map the value (should be faster and use less memory than separate filter and map)
var total_percents = cars.reduce(
function(out, element) {
var savings_percent = Number(element[0].getAttribute("percent-savings"));
if (savings_percent > 0) {
// Only add to the out-array if value is greater than 0.
out.push(savings_percent);
}
return out;
},
[] // start with empty array
);
total_percents will be an array, with values that is greater than 0.
Reading from a comment on another answer, what you wanted was the max savings.
Then I would do it like this:
var max_savings = cars.reduce(
function(value, element) {
var savings_percent = Number(element[0].getAttribute("percent-savings"));
return Math.max(savings_percent, value)
},
0 // start with no savings
);
"Number" will return "NaN" (Not a Number) if the argument cannot be converted to a number. Then you are using numeric comparison ">" of a string "NaN" to your zero value, so that comparison fails and does not return, therefore the "undefined" occurs. You could do a double comparison - if (typeof savings_percent == 'string'
if (typeof savings_percent == 'number' && savings_percent > 0)

Javascript sorting a date (mm/dd/yyyy) not working in chrome browser

How do I sort below array of dates in ascending as well as descending order? For example, I have:
var value = [
{"ID":"3","date":null},
{"ID":"24","date":"07/28/2017"},
{"ID":"65","date":"05/14/2018"},
{"ID":"36","date":"06/11/2017"},
{"ID":"27","date":null},
{"ID":"18","date":"02/26/2018"},
{"ID":"37","date":null},
{"ID":"39","date":"05/15/2017"},
{"ID":"10","date":"06/11/2017"},
{"ID":"4","date":null},
{"ID":"8","date":null},
{"ID":"12","date":"05/15/2017"},
{"ID":"14","date":"07/28/2017"},
{"ID":"19","date":"06/11/2017"}
];
I'd like the resultant array to look like:
var result = [
{"ID":"3","date":null},
{"ID":"27","date":null},
{"ID":"4","date":null},
{"ID":"8","date":null},
{"ID":"39","date":"05/15/2017"},
{"ID":"12","date":"05/15/2017"},
{"ID":"36","date":"06/11/2017"},
{"ID":"10","date":"06/11/2017"},
{"ID":"19","date":"06/11/2017"}
{"ID":"24","date":"07/28/2017"},
{"ID":"14","date":"07/28/2017"},
{"ID":"18","date":"02/26/2018"},
{"ID":"65","date":"05/14/2018"}
];
Javascript sorting function :
function sortArray(desc, value) {
if (desc) {
value.sort(function(a: any, b: any) {
let aValue = (a["date"]) ? Number(new Date(a["date"])) : Number(new Date(0));
let bValue = (b["date"]) ? Number(new Date(b["date"])) : Number(new Date(0));
return bValue - aValue;
});
} else {
value.sort(function(a: any, b: any) {
let aValue = (a["date"]) ? Number(new Date(a["date"])) : Number(new Date(0));
let bValue = (b["date"]) ? Number(new Date(b["date"])) : Number(new Date(0));
return aValue - bValue;
});
}
}
I have mention input array as well as expected array.Thanks in advance.
You can use ES6 syntax, and play with .reverse() to get ASC or DESC
value.sort((a, b) => new Date(b.date) - new Date(a.date)).reverse()
Demo - https://jsfiddle.net/zkcsdv01/
or look here for more extended answer Sort Javascript Object Array By Date

Javascript - Sorting array with objects based on objects value

So I am trying to sort my array with objects based on an objects value..
var mostCheapHistory [ { lowestTitle: title goes here, lowestPrice: 100 }, another obj, another, another } ]
And I want to sort them based on their price, so I came up with this:
var historyObj = mostCheapHistory[0];
for(var y in mostCheapHistory){
nextObj = mostCheapHistory[y];
console.log('Is '+ historyObj.lowestPrice + ' more as ' + nextObj.lowestPrice + ' ?');
console.log(historyObj.lowestPrice > nextObj.lowestPrice);
console.log('-----')
}
And this is the output...
Is 124.98 more as 124.98 ?
false
-----
Is 124.98 more as 18.59 ?
false
-----
Is 124.98 more as 25.9 ?
false
-----
Is 124.98 more as 26.99 ?
false
-----
Is 124.98 more as 34.76 ?
false
-----
What the hell is going on? It's obvious that 124.98 is more as 34.76 and yet it gives false?
The array is made using this code:
for(var x=0; x < items.length; x++){
var title = items[x].title[0];
var price = items[x].sellingStatus[0].currentPrice[0].__value__;
var item =
{
lowestPrice : price,
lowestTitle : title
}
if(x === 0){
mostCheapHistory.push(item);
}
else{
for(var y=0; y < mostCheapHistory.length; y++){
if(mostCheapHistory[y].lowestPrice > price ){
if(mostCheapHistory.length < 5){
mostCheapHistory.push(item);
break;
}
else{
mostCheapHistory[y] = item;
break;
}
}
}
}
}
Use the predefined sort function :
mostCheapHistory.sort(function(a,b){
return a.lowestPrice - b.lowestPrice;
}
+ Your code might be pushing strings rather than numbers, which explains why 124.98 > 34.76 => true but '124.98' > '34.76' => false, since the string '34.76' is greater than '124.98' in string comparison.
Use parseFloat() for the prices then check again.
It looks like, you are comparing strings instead of numerical values. If you say (in comments), that the sorting function
array.sort((a, b) => a.lowestPrice - b.lowestPrice);
solves your problem, then while this sort callback uses an implicit casting to number with the minus - operator.
The result is a sorted array with values as string.
You can sort these based on price using Array.prototype.sort() (See MDN documentation)
e.g.
var data = [
{
title: "title1",
value: 123
},
{
title: "title2",
value: 324
},
{
title: "title3",
value: 142
}];
var sorted = data.sort(function(a, b) {
return a.value > b.value;
});
I think the type of lowestPrice is string not float, use parseFloat(historyObj.lowestPrice) to compare the two values

why array is not sorted in javascript in increasing date or decreasing date?

I am trying to sort my array of objects .Objects have date property.I need to sort my array in ascending or descending dates .I try like this
https://jsfiddle.net/rxaLutgn/1/
function sort_by(field, reverse, primer) {
var key = primer ?
function (x) {
return primer(x[field])
} :
function (x) {
return x[field]
};
reverse = !reverse ? 1 : -1;
return function (a, b) {
return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
}
}
It not sorted array in ascending or descending order.
Your function is pretty messed up, try
function sort_by(field, reverse, primer) {
var key = primer ?
function (x) {
return primer(x[field])
} :
function (x) {
return x[field]
};
reverse = !reverse ? 1 : -1;
return function (a, b) {
a = new Date(key(a)), b = new Date(key(b));
return reverse * (a-b);
}
}
You need to convert date strings to date to sort and also you need to change your return code.
Working fiddle
The function works fine if you are expecting all dates. Looking at your data there are some invalid dates like "-"
If you can't modify the data or expect a definite date always then you need to mod your function to do something like this (or handle it in some way to your liking)
function sort_by(field, reverse, primer) {
var key = primer ?
function (x) {
return primer(x[field])
} :
function (x) {
return x[field]
};
reverse = !reverse ? 1 : -1;
return function (a, b) {
a = new Date(key(a))=='Invalid Date'?0:new Date(key(a));
b = new Date(key(b))=='Invalid Date'?0:new Date(key(b));
return reverse * (a-b);
}
}
All props to #void for his answer. I just updated since there was a duplicate question raised for this and I don't have rep to comment on the question or on #void's answer on this post

Categories

Resources