I have a range of numbers as follows:
const a = ["11-50", "2-10", "1", "51-200"]
I would like to sort them properly like
["1", "2-10", "11-50", "51-200"]
I have tried both of these sort methods to no avail:
a.sort((a, b) => a - b)
a.sort()
We can try sorting on the lower bound number in each range:
const input = ["11-50", "2-10", "1", "51-200"];
input.sort(function(a, b) {
return parseInt(a.split("-")[0]) - parseInt(b.split("-")[0]);
});
console.log(input);
Disclaimer: parseInt may not always do what you want, but with this example it should work!
a.sort((a, b) => parseInt(a) - parseInt(b));
A little more formally, write some code to change representation from strings to numbers and back...
const string2Range = string => string.split('-').map(parseInt);
const range2String = range => `${range[0}-${range[1]}`;
Define what makes a range smaller than another...
// low value?
const compLow = (rangeA, rangeB) => rangeA[0] - rangeB[0]
// midpoint value?
const midpoint = range => (range[1] - range[0]) / 2;
const compMid = (rangeA, rangeB) => midpoint(rangeA) - midpoint(rangeB);
// something else??
Then transform, sort, transform back (assuming string output is desired)
let input = ["11-50", "2-10", "1", "51-200"]
let ranges = input.map(string2Range);
ranges.sort(compLow); // or another you define
let output = ranges.map(range2String)
You could match numbers and if two numbers are available, take it for an adjusted sort.
Try this snippet-
a = ["11-50", "2-10", "1", "51-200"]
a.sort(function (a, b) {
function getV(v) { return v.match(/\d+/g); }
var aa = getV(a),
bb = getV(b);
return aa[0] - bb[0] || (aa[1] || aa[0]) - (bb[1] || bb[0]);
});
console.log(a)
Related
say that I have:
var arr = ['-1254', '+2343']
I want my sum to be 1,089
I tried parseInt(arr.reduce((a, b) => a + b, 0)) but it returns 0.
How can find the sum of arr?
You got 0 because in arr.reduce() initial a value is 0 number type. but b is current value that is '-1245' is string. So that's why it's not calculate.
If you want to calculate it properly you need to make b as an integer. Like this.
var result = arr.reduce((a, b) => a + parseInt(b), 0)
then log this.
Thank you
you need to convert string into number first.
var arr = ['-1254', '+2343']
arr.reduce((a, b) => a *1 + b * 1,0)
My array:
const a = [
{
"baseFare": "1439.00",
},
{
"baseFare": "1739.00",
},
{
"baseFare": "1039.00",
},
]
Note: The number of values in const a will increase or decrease its user decisions ! there may be one or 5 or 7 values in the array !
How to sum all the values and output a single value , and in somecase if its only one value then the out put should be direct single value !
How to achive this ?
My code :
a.reduce((a, b) => a + b, 0)
you are almost there
try this,
a.reduce((a, b) => a + (+b.baseFare), 0);
//a is the accumulator , and it start with 0 its an integer
//If you need to access baseFare, then you have to get it from object b.baseFare,
//b.baseFare is a string so you have to convert it to a number (+b.baseFare) is for that
if you really need to get it as a floating point number, for ex: 5000, showing as "5000.00" then try this out
let sum = a.reduce((a, b) => a + (+b.baseFare), 0);;
sum = sum.toFixed(2); //"4217.00"
Just loop, converting the strings to numbers as you go:
let result = 0;
for (const entry of a) {
result += +entry.baseFare;
}
Or with destructuring:
let result = 0;
for (const {baseFare} of a) {
// ^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−− destructuring
result += +baseFare;
}
That unary + is just one way to convert from string to number. I go into all your options in this other answer.
I have function taken from this example here that works well, except does not address any zeros that may be in the number, so everything is equaling zero when executing the function.
Multiplying individual digits in a number with each other in JavaScript
function digitsMultip(data) {
let arr = [];
for (let i of data) {
if (data[i] === 0) {
arr.push(data[i]);
}
}
return [...data.toString()].reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
I added to it a for-loop that accounts for the zero and remove it, but im doing something wrong here.
Uncaught TypeError: data is not iterable
DESIRED OUTPUT
3025 => 3 * 2 * 5 = 30
This iterates over the characters in your number. If the character is not "0" then it is added to the array. This array is then reduced by multiplying the values and then returned.
function digitsMultip(data) {
const arr = [];
for(let number of String(data)) {
if (number !== "0")
arr.push(number);
}
return arr.reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
You are getting that error because you are trying to iterate over a number.
Passing in a string or converting the number to string before iterating it would make it work.
Instead of looping it that way, a better and readable way would be to use the filter method to filter out the chars before multiplying:
function digitsMultip(data) {
return [...data.toString()].filter(n => n > '0').reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
Turn the input into a string, then split, filter the zeros and reduce multiplying
const input = 1203
const removeZeros = number =>{
const arr = number.toString().split('').filter(i => i !== '0')
return arr.reduce((a,c) => parseInt(a) * parseInt(c))
}
console.log(removeZeros(input))
One line version
const removeZeros = n => [...n.toString()].filter(c => c !== '0').map(x => parseInt(x)).reduce((a,c) => a*c)
I'm working on a small machine learning theoretical algorithm using nodeJs.
My goal is to compare many array patterns to one source pattern then return how
similar they are represented as a percent . For an example pattern1 maybe 80% similar to the source pattern .
What can be the best method for determining percent similarity for one array to another?
What I've done so far..
//source
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]
//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]
Since I've chosen a percent based outcome , I figured I should base my source pattern off percentage change from first value to second value in array .
var percentChange = (firstVal, secondVal) => {
var pChange = ((parseFloat(secondVal) - firstVal) /
Math.abs(firstVal)) * 100.00;
//To avoid NaN , Infinity , and Zero
if(!pChange || pChange == 0){
return 0.00000001
}
return pChange;
}
Here I will generate my source pattern from my source sequence
var storePattern = function(sequence){
var pattern = [];
for(var i = 0 ; i < sequence.length ; i++){
let $change = percentChange(sequence[i] , sequence[i + 1]);
if(i != sequence.length && $change ){
pattern.push($change)
}
}
return pattern;
}
var sourcePattern = storePattern(soureSequence);
Now I will create more patterns to be compared
var testPattern1 = storePattern(sequence1);
var testPattern2 = storePattern(sequence2);
Below is my comparison function
var processPattern = function(source , target){
var simularityArray = [];
for(var i = 0 ; i < target.length ; i++){
//Compare percent change at indexof testPattern to sourcePattern of same index
let change = Math.abs(percentChange(target[i] , source[i]));
simularityArray.push(100.00 - change);
}
var rating = simularityArray.reduce((a,b) => {
return a + b
});
//returns percent rating based of average of similarity pattern
rating = rating / parseFloat(source.length + ".00");
return rating;
}
Now I can try to estimate the similarity
var similarityOfTest1 = processPattern(sourcePattern , testPattern1)
My problem is that this only works on sequences within the same range of value .. for example 0.50 , 0.52 .. the percent change in these values would not be the same for 0.20 , 0.22 but the value difference is the same ie -> 0.02
I thought about a difference in value based pattern but at this point I'm lost.
All answers will be considered . Thanks for the help!
used reduce to get the difference than the average.
//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]
function diff(sequence){
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]
var delta = soureSequence.reduce(function (r, a, i, aa) {
i && r.push(a - sequence[i]);
return r;
}, []),
average = delta.reduce(function (a, b) { return a + b; }) / delta.length;
return {delta:delta, average:average}
}
console.log('sequence1',diff(sequence1));
console.log('sequence2',diff(sequence2));
In my experience, the similarity of two vectors (arrays) is measured using the dot product ex. Like it says in that link, you multiply each corresponding elements of the arrays, add those up, then divide by the magnitude of each array (square root of the sum of the squares of each component). Rosetta Code has an example of the dot product in JavaScript, copied here
// dotProduct :: [Int] -> [Int] -> Int
const dotProduct = (xs, ys) => {
const sum = xs => xs ? xs.reduce((a, b) => a + b, 0) : undefined;
return xs.length === ys.length ? (
sum(zipWith((a, b) => a * b, xs, ys))
) : undefined;
}
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => {
const ny = ys.length;
return (xs.length <= ny ? xs : xs.slice(0, ny))
.map((x, i) => f(x, ys[i]));
}
So, you would call
const score1 = dotProduct(sourceSequence, sequence1);
const score2 = dotProduct(sourceSequence, sequence2);
And whichever is bigger is the closer sequence to sourceSequence.
I'm not sure you need machine learning for this. You have a source pattern and you have some inputs and you basically want to perform a diff of the patterns.
Machine learning could be used to find the patterns, assuming you have some heuristic for measuring the error (if you're using unsupervised learning techniques) or you have sample sets to train the network.
But if you are simply wanting to measure the differences between one pattern and another pattern then just perform a diff operation. What you'll need to do is decide what differences your measuring and how to normalize the result.
I can't tell how exactly you would like to measure the similarity. I go by calculating the difference of corresponding items and accumulating these differences to see how much deviation it would result from the sum of the source array. You can play with the calculation the way you like.
function check([x,...xs],[y,...ys], state = {sumSource: 0, sumDiff: 0}){
state.sumSource += x;
state.sumDiff += Math.abs(x-y);
return xs.length ? check(xs,ys,state) : (100 - 100 * state.sumDiff / state.sumSource).toFixed(4) + "% similarity";
}
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60],
sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60],
sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62];
console.log(check(soureSequence,sequence1));
console.log(check(soureSequence,sequence2));
I currently have a set of strings that are both just numbers and number with + or -. Such as follows :
1 , 1+, 1-, 2, 2+, 2-, 10
Which when I sort using JavaScript's sort functions gives out:
1, 1+ , 1-, 10, 2, 2+, 2-
which is lexicographically orders but not numerically. Is there a way to sort this so the numbers come out in the correct way(the first list) ? I am using ExtJS stores so an answers as a store sorter is preferred but plain javascript is also fine. Thanks ?
Edit: This is not just sorting numbers.
You can use a custom ordering function like so:
var numbers = ['1', '1-', '1+', '2', '2+', '2-', '10'];
numbers.sort(function (a, b){
var _a = parseFloat(a), // If the values are integers only, parseInt will do too
_b = parseFloat(b);
if (_a - _b === 0) {
return (a > b) ? 1 : -1;
} else {
return _a - _b;
}
});
console.log(numbers);
The function checks whether the number values are equal, and if so, falls back to lexicographic ordering to sort the character suffixes. If there are no suffixes in equal-case, hence no matter in which order the numbers are returned. If only one of the operands has a suffix, bare number returns negative. If the number values are not equal, the function simply returns the tristate, i.e a - b, which will be evaluated to one of negative, 0, positive. Or actually it's "bistate", since we've handled 0 case already.
More generic solution
The code above is rather a special case for two different single charactered suffixes only. If suffixes are more complex, here's a more generic code to sort by number and by suffixes:
var numbers = ['1', '1-r', '1+q', '1', '2', '2+q', '2-r', '10'];
function suffixSort (suff, asc) {
asc = 2 * +(!!asc) - 1; // Convert boolean to -1 or 1
return function (a, b) {
var _a = parseFloat(a), // Extract the number value
_b = parseFloat(b),
aSI = -(a.length - _a.toString().length), // Get the index of suffix start
bSI = -(b.length - _b.toString().length);
// Equal number values, sort by suffixes
if (_a === _b) {
return (suff.indexOf(a.substr(aSI)) > suff.indexOf(b.substr(bSI))) ? 1 : -1;
}
// Inequal number values, sort by numbers
return asc * (_a - _b);
}
}
// suffixSort arguments
// suff: An array of the suffix strings to sort, ordered in the desired sorting order
// asc: true = ascending, false = descending. Optional, defaults to descending sort
numbers.sort(suffixSort(['+q', '-r'], true));
console.log(numbers);
The idea is to store the suffixes into an array, and when suffix sorting is needed, function compares the array indices of the suffixes instead of the suffixes themselves.
suffixSort lets you also to decide the sorting direction. Selected sorting direction doesn't have an effect on suffix sorting, they are always returned in the order they appear in suff array.
These values are almost integers, so comparing them according to praseInt will almost get you there. The only thing missing is a special treatment for values that have the same integer part where x- should come first, then x and finally x+:
function specialChar(s) {
c = s.substr(-1);
if (c == '+') {
return 1;
}
if (c == '-') {
return -1;
}
return 0;
}
function numCompare(a, b) {
aNum = parseInt(a);
bNum = parseInt(b);
cmp = aNum - bNum;
if (cmp != 0) {
return cmp;
}
// Integer parts are equal - compare the special char at the end
return specialChar(a) - specialChar(b);
}
arr = ['1' , '1+', '1-', '2', '2+', '2-', '10'];
arr.sort(numCompare);
var result=[];
result=array.map(function(n){
if(typeof n==='number') return n;
if(n[n.length-1]=='+'){
return parseInt(n.substring(0,n.length-1))
}
else if(n[n.length-1]=='-'){
return 0-parseInt(n.substring(0,n.length-1))
}
});
result.sort(function(a,b){return a-b})
You could use Array#sort and split the elements in numbers and the rest, then return the difference or the difference of the order.
var array = ['10', '2', '2+', '2-', '1', '1+', '1-'];
array.sort(function (a, b) {
var r = /\d+|\D+/g,
aa = a.match(r),
bb = b.match(r),
order = { '+': 1, '-': 2 };
return aa[0] - bb[0] || (order[aa[1]] || 0) - (order[bb[1]] || 0);
});
console.log(array);
If there are only three possible states of a number, and the states have the order number, number+, number the states can be recreated by creating an array representation of the numbers, removing the unique numbers from array, from minimum to maximum, concatenating empty string or arithmetic operator in required order to the number, then pushing the value to an array, where .toString() can be used to view the comma separated string representation of the sorted values within the array
var str = `314+, 1-, 7+, 1, 1-, 271-, 10-
, 10+, 271, 271+, 314-, 314
, 10, 2-, 2, 2+, 7-, 7`;
for (var [nums, order, res, num] = [str.match(/\d+/g), ["", "+", "-"], [], null]
; nums.length
; num = Math.min.apply(Math, nums)
, res = [...res, ...order.map(op => num + op)]
, nums = nums.filter(n => n != num)
);
console.log(res.toString() + "\n", res);
Assuming that you just want to throw away the symbols, then you could use parseInt and Array#sort to get order numerically.
var data = ['1' , '1+', '1-', '2', '2+', '2-', '10'];
var sortedData = data.sort(function(a,b){return parseInt(a)-parseInt(b);});