Simplify semver version compare logic - javascript

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;
};

Related

properly override toJSON for mathjs bignumber

I am trying to override mathjs Bignumber using:
import * as math from 'mathjs';
export const bgn = (v: number | math.BigNumber) => {
const z = math.bignumber(v) as math.BigNumber;
(z as any).toJSON = () => {
return Number(math.larger(100, z) ? math.round(z,2) : math.round(z,4)).toFixed(4);
}
return z;
}
but for some reason, it's still stringifying it to:
{"mathjs":"BigNumber","value":"42500"}
my goal is to stringify it to a number:
42500
This is not currently possible with the native JSON.stringify implementation. It will become possible with the adoption of the JSON.parse source text access proposal which also includes a helper for non-lossy serialization.
You'd use it as
const text = JSON.stringify(value, (key, val) => {
if (val instanceof math.bignumber) return JSON.rawJSON(val.toString())
else return val;
});
console.log(text);
OP was on the right track, this should work fine:
const math = require('mathjs');
const bgn = (v) => {
const z = math.bignumber(v); // as math.BigNumber;
(z).toJSON = () => {
return Number(math.larger(z, 100) ? math.round(z, 3) : math.round(z, 5));
}
return z;
}
console.log(JSON.stringify(bgn(5.555555444)));
in JS instead of TS.

Store value in a variable

I am new in Javascript. I develop a program that store the score of humun and computer guess number. I want the human score and computer score will update when I call the updateScore() functions. However, it works but the score unable to increase by last score.
Here is the code:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random()*10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humunGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humunTarget = Math.abs(humunGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humunTarget < computerTarget || humunTarget == computerTarget) {
return true;
}
else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore+=1;
case false:
computerScore+=1;
}
};
updateScore()
console.log(humanScore)
console.log(computerScore)
It is a programming language based on javascript event/trigger features. all variables are reset when you call the file again.
The variables seem to be reset every time you call the javascript file
let humanScore = 0,
computerScore = 0,
currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humanGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humanTarget < computerTarget) {
return true;
} else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore += 1;
case false:
computerScore += 1;
}
};
let showScore = () => {
updateScore();
console.log(humanScore)
console.log(computerScore)
}
<button onclick="showScore()">Click</button>
Woking Demo : https://jsfiddle.net/6v25y9qd/
Push click and show console
Because you're new, and I think #Onur Özkır is on to something, I will give some guidelines instead.
I understand that you mostly trying out to see if things works, and will refactor afterwards, but I recommend that you create methods that does only one thing. You already done that with generateTarget(), but if I look at compareGuesses(), that method doesn't just compare guesses. It also reads and generates numbers. I would instead read the values in updateScore() and then add them as parameters in compareGuesses.
By restricting your methods to only do one thing will make your code more readable, your methods will be smaller so they are easier to grasp, and the code is easier to debug.
I would also like to suggest that you only return a value at the end of the method, and always return (unless you can fit everything on one row) using a variable.
I also don't like switches in javascript, because the forced use of return. Would rather use ifs statement or a shorthand if statements, using conditional/ternary operator.
Use method names and variables to explain the code (ex. the constant HUMAN_WON in the code below). Try to avoid comments as far as possible. Comments should, IMHO, only be used if you generate a documentation. I suggest that you get your hands on Clean Code, which was a revelation for me to read, even as an experienced programmer.
I will refactor your code as a suggestion of how it can look like:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
};
let displayCurrentScore = () => {
updateScore();
console.log(`${humanScore} vs ${computerScore}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">
You can even go one step further refactoring readGuesses() from updateScore() and separate updating UI—displayCurrentScore()—from handling logic in updateScore().
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const readGuesses = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
return [humanGuess, computerGuess, secretTargetNumber]; // returning array
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = (humanGuess, computerGuess, secretTargetNumber) => {
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
return {'human': humanScore, 'computer': computerScore};
};
let displayCurrentScore = () => {
let [humanGuess, computerGuess, secretTargetNumber] = readGuesses();
let score = updateScore(humanGuess, computerGuess, secretTargetNumber);
console.log(`${score.human} vs ${score.computer}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">

Multiple brackets function with rest parameter in JavaScript [duplicate]

I need a js sum function to work like this:
sum(1)(2) = 3
sum(1)(2)(3) = 6
sum(1)(2)(3)(4) = 10
etc.
I heard it can't be done. But heard that if adding + in front of sum can be done.
Like +sum(1)(2)(3)(4). Any ideas of how to do this?
Not sure if I understood what you want, but
function sum(n) {
var v = function(x) {
return sum(n + x);
};
v.valueOf = v.toString = function() {
return n;
};
return v;
}
console.log(+sum(1)(2)(3)(4));
JsFiddle
This is an example of using empty brackets in the last call as a close key (from my last interview):
sum(1)(4)(66)(35)(0)()
function sum(firstNumber) {
let accumulator = firstNumber;
return function adder(nextNumber) {
if (nextNumber === undefined) {
return accumulator;
}
accumulator += nextNumber;
return adder;
}
}
console.log(sum(1)(4)(66)(35)(0)());
I'm posting this revision as its own post since I apparently don't have enough reputation yet to just leave it as a comment. This is a revision of #Rafael 's excellent solution.
function sum (n) {
var v = x => sum (n + x);
v.valueOf = () => n;
return v;
}
console.log( +sum(1)(2)(3)(4) ); //10
I didn't see a reason to keep the v.toString bit, as it didn't seem necessary. If I erred in doing so, please let me know in the comments why v.toString is required (it passed my tests fine without it). Converted the rest of the anonymous functions to arrow functions for ease of reading.
New ES6 way and is concise.
You have to pass empty () at the end when you want to terminate the call and get the final value.
const sum= x => y => (y !== undefined) ? sum(x + y) : x;
call it like this -
sum(10)(30)(45)();
Here is a solution that uses ES6 and toString, similar to #Vemba
function add(a) {
let curry = (b) => {
a += b
return curry
}
curry.toString = () => a
return curry
}
console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1)(2)(3)(4))
Another slightly shorter approach:
const sum = a => b => b? sum(a + b) : a;
console.log(
sum(1)(2)(),
sum(3)(4)(5)()
);
Here's a solution with a generic variadic curry function in ES6 Javascript, with the caveat that a final () is needed to invoke the arguments:
const curry = (f) =>
(...args) => args.length? curry(f.bind(0, ...args)): f();
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1)() == 5 // true
Here's another one that doesn't need (), using valueOf as in #rafael's answer. I feel like using valueOf in this way (or perhaps at all) is very confusing to people reading your code, but each to their own.
The toString in that answer is unnecessary. Internally, when javascript performs a type coersion it always calls valueOf() before calling toString().
// invokes a function if it is used as a value
const autoInvoke = (f) => Object.assign(f, { valueOf: f } );
const curry = autoInvoke((f) =>
(...args) => args.length? autoInvoke(curry(f.bind(0, ...args))): f());
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1) + 0 == 5 // true
Try this
function sum (...args) {
return Object.assign(
sum.bind(null, ...args),
{ valueOf: () => args.reduce((a, c) => a + c, 0) }
)
}
console.log(+sum(1)(2)(3,2,1)(16))
Here you can see a medium post about carried functions with unlimited arguments
https://medium.com/#seenarowhani95/infinite-currying-in-javascript-38400827e581
Try this, this is more flexible to handle any type of input. You can pass any number of params and any number of paranthesis.
function add(...args) {
function b(...arg) {
if (arg.length > 0) {
return add(...[...arg, ...args]);
}
return [...args, ...arg].reduce((prev,next)=>prev + next);
}
b.toString = function() {
return [...args].reduce((prev,next)=>prev + next);
}
return b;
}
// Examples
console.log(add(1)(2)(3, 3)());
console.log(+add(1)(2)(3)); // 6
console.log(+add(1)(2, 3)(4)(5, 6, 7)); // 28
console.log(+add(2, 3, 4, 5)(1)()); // 15
Here's a more generic solution that would work for non-unary params as well:
const sum = function (...args) {
let total = args.reduce((acc, arg) => acc+arg, 0)
function add (...args2) {
if (args2.length) {
total = args2.reduce((acc, arg) => acc+arg, total)
return add
}
return total
}
return add
}
document.write( sum(1)(2)() , '<br/>') // with unary params
document.write( sum(1,2)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)() , '<br/>') // with unary params
document.write( sum(1)(2,3)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)(4)() , '<br/>') // with unary params
document.write( sum(1)(2,3,4)() , '<br/>') // with ternary params
ES6 way to solve the infinite currying. Here the function sum will return the sum of all the numbers passed in the params:
const sum = a => b => b ? sum(a + b) : a
sum(1)(2)(3)(4)(5)() // 15
function add(a) {
let curry = (b) => {
a += b
return curry;
}
curry[Symbol.toPrimitive] = (hint) => {
return a;
}
return curry
}
console.log(+add(1)(2)(3)(4)(5)); // 15
console.log(+add(6)(6)(6)); // 18
console.log(+add(7)(0)); // 7
console.log(+add(0)); // 0
Here is another functional way using an iterative process
const sum = (num, acc = 0) => {
if !(typeof num === 'number') return acc;
return x => sum(x, acc + num)
}
sum(1)(2)(3)()
and one-line
const sum = (num, acc = 0) => !(typeof num === 'number') ? acc : x => sum(x, acc + num)
sum(1)(2)(3)()
You can make use of the below function
function add(num){
add.sum || (add.sum = 0) // make sure add.sum exists if not assign it to 0
add.sum += num; // increment it
return add.toString = add.valueOf = function(){
var rtn = add.sum; // we save the value
return add.sum = 0, rtn // return it before we reset add.sum to 0
}, add; // return the function
}
Since functions are objects, we can add properties to it, which we are resetting when it's been accessed.
we can also use this easy way.
function sum(a) {
return function(b){
if(b) return sum(a+b);
return a;
}
}
console.log(sum(1)(2)(3)(4)(5)());
To make sum(1) callable as sum(1)(2), it must return a function.
The function can be either called or converted to a number with valueOf.
function sum(a) {
var sum = a;
function f(b) {
sum += b;
return f;
}
f.toString = function() { return sum }
return f
}
function sum(a){
let res = 0;
function getarrSum(arr){
return arr.reduce( (e, sum=0) => { sum += e ; return sum ;} )
}
function calculateSumPerArgument(arguments){
let res = 0;
if(arguments.length >0){
for ( let i = 0 ; i < arguments.length ; i++){
if(Array.isArray(arguments[i])){
res += getarrSum( arguments[i]);
}
else{
res += arguments[i];
}
}
}
return res;
}
res += calculateSumPerArgument(arguments);
return function f(b){
if(b == undefined){
return res;
}
else{
res += calculateSumPerArgument(arguments);
return f;
}
}
}
let add = (a) => {
let sum = a;
funct = function(b) {
sum += b;
return funct;
};
Object.defineProperty(funct, 'valueOf', {
value: function() {
return sum;
}
});
return funct;
};
console.log(+add(1)(2)(3))
After looking over some of the other solutions on here, I would like to provide my two solutions to this problem.
Currying two items using ES6:
const sum = x => y => (y !== undefined ) ? +x + +y : +x
sum(2)(2) // 4
Here we are specifying two parameters, if the second one doesnt exist we just return the first parameter.
For three or more items, it gets a bit trickier; here is my solution. For any additional parameters you can add them in as a third
const sum = x => (y=0) => (...z) => +x + +y + +z.reduce((prev,curr)=>prev+curr,0)
sum(2)()()//2
sum(2)(2)()//4
sum(2)(2)(2)//6
sum(2)(2)(2,2)//8
I hope this helped someone

Sorting different arrays in typescript

I am trying to sort some parameter in my typescript model. My model is as follows.
export class DataModel {
ID: String
point1: Point
point2 : Point
point3: Point
AnotherPoint1: AnotherPoint[]
AnotherPoint2: AnotherPoint[]
AnotherPoint3: AnotherPoint[]
}
export class Point {
Name: String
Timestamp: String
}
export class AnotherPoint {
Name: String
Timestamp: String
}
I have sorting logic in my component which take this above Data Model and sorts point as follows:
private sortByNameAndID(dataModel: DataModel[]): DataModel[] {
return dataModel.sort(function (a, b) {
const pointA = a.point1.Name.toLowerCase();
const pointB = b.point1.Name.toLowerCase();
if (pointA === pointB) {
const timeA = a.point1.Timestamp;
const timeB = b.point1.Timestamp;
return Service.compareDate(new Date(timeA), new Date(timeB)); //here again comparing dates
}
if (pointA < pointB ) {
return -1;
}
if (pointA > pointB ) {
return 1;
}
});
}
}
Above sorting logic is working fine for Points but now with this I also need to sort AnotherPoint as well. Means I have to sort all Points and AnotherPoints together as above. How can I do that?
I would start creating two helper functions, to compare two Points and two arrays of AnotherPoints respectively. I'm assuming that the arrays are to be compared element by element, stopping as soon as a pair of elements does not compare to 0.
function comparePoints(pA: Point | AnotherPoint, pB: Point | AnotherPoint)
{
const pointA = pA.Name.toLowerCase();
const pointB = pB.Name.toLowerCase();
if (pointA < pointB ) {
return -1;
}
if (pointA > pointB ) {
return 1;
}
const timeA = pA.Timestamp;
const timeB = pB.Timestamp;
return Service.compareDate(new Date(timeA), new Date(timeB));
}
function comparePointArrays(arrayA: AnotherPoint[], arrayB: AnotherPoint[])
{
const len = Math.min(arrayA.length, arrayB.length);
for (let i = 0; i < len; ++i)
{
const result = comparePoints(arrayA[i], arrayB[i]);
if (result !== 0) {
return result;
}
}
return 0;
}
Then the sorting function can be rewritten using the new helper comparators:
private sortByNameAndID(dataModel: DataModel[]): DataModel[] {
return dataModel.sort(function (a, b) {
return comparePoints(a.point1, b.point1) ||
comparePoints(a.point2, b.point2) ||
comparePoints(a.point3, b.point3) ||
comparePointArrays(a.AnotherPoint1, b.AnotherPoint1) ||
comparePointArrays(a.AnotherPoint2, b.AnotherPoint2) ||
comparePointArrays(a.AnotherPoint3, b.AnotherPoint3);
});
}
Note that the || operator only performs the operation on the right if the result of the operation on the left is falsy (0), meaning that we will stop comparing points as soon as a comparison reports a nonzero result.

JS chaining functions

I'm writing a function that should work like this:
checker(3).equals(3) // true
checker(3).not().equals(3) // false
checker(3).not().equals(4) // true
checker(3).not().not().equals(4) // false
The code I came up with:
function checker(num) {
let number = num
return {
not() {
number = !number
return this
},
equals(nmb) {
return number === nmb
}
}
}
I can't wrap my head around what should not() do so as to make checker(num) work as it is supposed to.
You can add another boolean property that changes how equals works depending on it's value.
function checker(num) {
let number = num
let not = false
return {
not() {
not = !not
return this
},
equals(nmb) {
return not ? number !== nmb : number === nmb
}
}
}
console.log(checker(3).equals(3)) // true
console.log(checker(3).not().equals(3)) // false
console.log(checker(3).not().equals(4)) // true
console.log(checker(3).not().not().equals(4)) // false
Maybe somthing like this:
function checker(num) {
let number = num
let beTrue = true;
return {
not() {
beTrue = !beTrue;
return this
},
equals(nmb) {
return (number === nmb) === beTrue;
}
}
}
It seems to fullfil your requirements. Hope it helps
An ES6 approach
const checker=(number, negate)=>{
const neg = negate || false;
return {
not(){
return checker(number, !neg);
},
equals(number2){
if (neg) return number != number2;
return number == number2;
}
}
}
what should not() do so as to make checker(num) work as it is supposed to.
not could return a new checker.
I think i would let the notfunction control the operator, something like
function checker(num) {
let operator = 'equals';
let number = num
return {
not() {
if(operator==='equals')
operator = 'not equals';
else
operator = 'equals';
return this
},
equals(nmb) {
if(operator==='equals')
return number === nmb
else
return number !== nmb
}
}
}
just using a string as operator for clarity, a proberly better solution could be to use a boolean or number value

Categories

Resources