Efficiently convert string based time into milliseconds - javascript

I was given a challenge, to create a function that'd convert a string based time into milliseconds.
That's the string format I was given:
"hours:minutes:seconds.milliseconds"
So this value for example will need to return 3010220.
"0:50:10.220"
The function needs to be short and one lined.
I'd love to know where I could improve the function below as it didn't pass the criteria. how can this be turned into a one liner?
function toMilliseconds(time){
return time.match(/[0-9]+/g).map(function(val,s,a){
return s != 3 ? +val * ((Math.pow(60,a.length - s -2) * 1000)) : +val;
}).reduce(function(a,b){
return a+b;
},0);
}

There are many different ways.
This is the shortest way I can think of (using ES6):
var str = "0:50:10.220";
var ms = (s=>1E3*s[2]+6E4*s[1]+36E5*s[0])(str.split(':'));
console.log(ms);

And another one:
let ms = str.split(':').reduce((a,v,i) => a + v * [3600000, 60000, 1000, 1][i], 0)
EDIT, thanks to #Swonkie:
let ms = str.split(':').reduce((a,v,i) => a + v * [3600000, 60000, 1000][i], 0)
Which leads to (thanks #Arnauld):
let ms = str.split(':').reduce((a,v,i)=>a+v*1E3*[3600,60,1][i],0);
Or, with rounding (not at all tested for validity):
let ms = str.split(':').reduce((a,v,i)=>a+v*1E3*[3600,60,1][i],0.5)|0;

As described here:
https://codereview.stackexchange.com/questions/45335/milliseconds-to-time-string-time-string-to-milliseconds
this looks like good solution:
function timeString2ms(a,b){// time(HH:MM:SS.mss) // optimized
return a=a.split('.'), // optimized
b=a[1]*1||0, // optimized
a=a[0].split(':'),
b+(a[2]?a[0]*3600+a[1]*60+a[2]*1:a[1]?a[0]*60+a[1]*1:a[0]*1)*1e3 // optimized
}
"oneline solution"
function timeString2ms2(a,b){ return a=a.split('.'),b=a[1]*1||0,a=a[0].split(':'),b+(a[2]?a[0]*3600+a[1]*60+a[2]*1:a[1]?a[0]*60+a[1]*1:a[0]*1)*1e3 }
Usage
console.log(timeString2ms('10:21:32.093')); // hh:mm:ss.mss
console.log(timeString2ms('21:32.093')); // mm:ss.mss
console.log(timeString2ms('21:32')); // mm:ss
console.log(timeString2ms('32.093')); // ss.mss
console.log(timeString2ms('32')); // ss
console.log(timeString2ms('32467.784')); // seconds.ms
console.log(timeString2ms(32467.784+'')); // seconds.ms

Related

Method implementation that takes 3 parameters and returns a binary number

I found a method that converts 1 number to a binary number.
function dec2bin(dec){
return (dec >>> 0).toString(2);
}
How to implement a method that takes 3 parameters (or more if possible) and turns them into one binary number.
for example:
Encrypt user with parameters
Age (up to 255-> 11111111)
Number of vacations (up to 15-> 1111)
On vacation or not (1 or 0)
create(30, 13, 1);
Expected to get 3 stacked together (00011110) (1101) (1): 0001111011011
According to your requirement Encrypt user with parameters age (up to 255-> 11111111), Number of vacations (up to 15-> 1111), On vacation or not (1 or 0)
const create = (age, noOfVacations, onVacation) => {
return (
age.toString(2).padStart(8, '0') +
noOfVacations.toString(2).padStart(4, '0') +
onVacation.toString(2).padStart(1, '0')
);
};
const ret = create(30, 13, 1);
console.log(ret);
By the way, you can refactor the above code to make it more reusable by making a separated binary to decimal with zero padding function.
const binToDecWithZeroPad = (param, n) => param.toString(2).padStart(n, '0');
const create = (age, noOfVacations, onVacation) =>
binToDecWithZeroPad(age, 8) +
binToDecWithZeroPad(noOfVacations, 4) +
binToDecWithZeroPad(onVacation, 1);
const ret = create(30, 13, 1);
console.log(ret);
If parameter number is unknown you can use rest parameter. Rest parameter syntax allows us to represent an indefinite number of arguments as an array. So you can use any number of parameter.
const create = (...params) => {
let str = '';
params.forEach((x) => (str += x.toString(2)));
return str;
};
const ret = create(30, 13, 1);
console.log(ret);
Update:
I have not to checked if the parameter is a non numeric, decimal or negative in my code because if you need to check it you can easily add it by using simple if condition and as for adding zero dynamically you cannot use more than one rest parameter because this is the limitation that only one rest parameter is allowed in the function declaration. Although, you can solve it by using one rest parameter(think about it if you have time). By the way, you can also use object, single or multiple array whatever you want as a parameter to make it dynamic.
This should work:
function dec2bin(dec){
return (dec >>> 0).toString(2);
}
function create(age, vacationNumber, vacation) {
var a = dec2bin(age).padStart(8, "0"); // padEnd adds zeros to match size
var b = dec2bin(vacationNumber).padStart(4, "0");
var c = vacation==true||vacation==1 ? 1 : 0;
return a + b + c;
}
console.log(create(15, 20, 1))
Here is a function encrypt that works on an array of any number of arguments, as long as you provide long enough encript digits array, and inputs are non-negative integers - if any of the conditions are not met, undefined is returned:
function dec2bin(dec, digits) {
if(typeof(dec)=="number" && dec%1==0 && dec>=0 && dec<Math.pow(2, digits))
return dec.toString(2).padStart(digits, "0");
return undefined;
}
function encrypt(userDetailsArray, encriptDigitsArray) {
if(userDetailsArray.length<=encriptDigitsArray.length) {
var result=(
userDetailsArray.map(
(detail, index) => dec2bin(detail, encriptDigitsArray[index])
)
);
if(result.includes(undefined))
return undefined;
else
return result.join("");
}
return undefined;
}
console.log(encrypt([30,13,1],[8,4,1])); /* your example */
console.log(encrypt([30,13],[8,4,1])); /* less input */
console.log(encrypt([30],[8,4,1])); /* even less input */
console.log(encrypt([30,13,1,100,5],[8,4,1,7,4])); /* more input and encript digits */
console.log(encrypt([999,13,1],[8,4,1])); /* bad input */
console.log(encrypt([30,13,1],[8,4])); /* not enough encript digits */
Decrypt (without testing validity of arguments):
function decrypt(bin, encriptDigitsArray) {
var result=[];
while(bin!="" && encriptDigitsArray.length) {
result.push(parseInt(bin.slice(0,encriptDigitsArray[0]), 2));
bin=bin.slice(encriptDigitsArray[0]);
encriptDigitsArray.shift();
}
return result;
}
console.log(decrypt("0001111011011",[8,4,1]));
console.log(decrypt("000111101101",[8,4,1]));
console.log(decrypt("00011110",[8,4,1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Add 0 before single digit number of time format [duplicate]

This question already has answers here:
Adding "0" if clock have one digit
(9 answers)
Closed 3 years ago.
How can we add 0 before single digit number of time format.
Like if I have a time "0:3:25" (hh:mm:ss) format to convert into "00:03:25"
You shouldn't overcomplicate this:
const time = "0:3:25";
const paddedTime = time.split(':').map(e => `0${e}`.slice(-2)).join(':')
console.log(paddedTime)
split the string by semicolons (:), that yields an array (hours, minutes, seconds). map this array with a function that adds a 0 before every item in the array, and slice the last two digits (you get an array again). Then join the resulting array by semicolons (and you get a string).
Or you could use a regex instead of the split:
const time = "0:3:25";
const paddedTime = time.match(/\d+/g).map(e => `0${e}`.slice(-2)).join(':')
console.log(paddedTime)
The last part is the same with regex (map, slice, join).
And you also could use the padStart() (JavaScript built-in function):
const time = "0:3:25";
const paddedTime = time.split(':').map(e => e.padStart(2, 0)).join(':')
console.log(paddedTime)
padStart() on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
You can do something like below (Explanations included):
const time = '0:3:25';
const correctedTime = parseTime(time);
console.log(correctedTime);
function parseTime(time){
return time
.split(':') // Split them into array as chunk of [hour, minute, second]
.map(pad) // Map them with `pad` function below
.join(':'); // Join them back into 'hh:mm:ss'
}
function pad(n){
return parseInt(n) < 10 // If number less than 10
? '0' + n // Add '0' in front
: n; // Else, return the original string.
}
you can add split the existing time string on the ":", then for each portion, add the "0" then take the last two characters. Then simply join the portions back into a striung.
let time = "0:3:25";
function updateTime(){
let newTimePortions = [];
let timePortions = time.split(":");
timePortions.forEach(function(portion,index) {
newTimePortions[index] = ("0" + portion).slice(-2)
})
return newTimePortions.join(':')
}
console.log(updateTime()); // gives 00:03:25
Please try below code
var dateinfo="0:3:25";
var newdate=dateinfo.split(":");
var hdate=newdate[0];
var mdate=newdate[1];
var sdate=newdate[2];
if(hdate.length == 1 ){
hdate="0"+hdate;
}
if(mdate.length == 1 ){
mdate="0"+mdate;
}
if(sdate.length == 1 ){
sdate="0"+sdate;
}
dateinfo=hdate+":"+mdate+":"+sdate;
This is work for me

How to create number suffixes such as "100K" without having to be repetitive?

I've been having a problem that when my auto clicker in my clicker game goes fast enough to get to 200 thousand, it starts to lag, and then it doesn't function properly, or as fast.
Is there a way to make 100 thousand turn into 100K, and 101 thousand turn into 101K without being repetitive?
I tried this with my original code, and realized putting up to 1000 suffixes into each function would be a little too hard:
if (number >= 100000) {
document.getElementById(ID).innerHTML = "100K"
}
if (number >= 101000) {
document.getElementById(ID).innerHTML = "101K"
}
and on and on.
I don't want multiple if statements!
This would work, but it would take up way too much space, and I know there is an easier way to it, but I just couldn't find it. Can anyone provide a way to do this?
Try separating the job of formatting your number into a different function.
SUFFIXES = 'KMBTqQsSOND' // or whatever you'd like them to be
function getSuffixedNumber(num) {
var power = Math.floor(Math.log10(num));
var index = Math.floor(power / 3);
num = Math.round(num / Math.pow(10, (index * 3))); // first 3 digits of the number
return num + (SUFFIXES[index - 1] || ''); // default to no suffix if we get an out of bounds index
}
You can call the function like this: var x = getSuffixedNumber(101000), the value of x will be "101K".

Sum Big Integers

I'm currently stuck on a Codewars challenge that I can't get my head around:
Given a string representation of two integers, return the string representation of those integers, e.g. sumStrings('1','2') // => '3'
I've used the following code so far, but it fails on large number test cases as the number is converted into a scientific notation:
function sumStrings(a,b) {
var res = +a + +b;
return res.toString();
}
Any help would be much appreciated.
Edit:
Fiddle example: https://jsfiddle.net/ag1z4x7d/
function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');
The problem is that in that specific kata (IIRC), the numbers stored in a and b are too large for a regular 32 bit integer, and floating point arithmetic isn't exact. Therefore, your version does not return the correct value:
sumStrings('100000000000000000000', '1')
// returns '100000000000000000000' instead of '100000000000000000001'
You have to make sure that this does not happen. One way is to do an good old-fashioned carry-based addition and stay in the digit/character based world throughout the whole computation:
function sumStrings(a, b) {
var digits_a = a.split('')
var digits_b = b.split('')
...
}

Why is this not a clear integer type and how to make it clear?

I have this code:
wallboard.data.Timer = function () {
$("div[data-value]").each(function () {
var time = $(this).attr("data-value");
if (time > 0) {
time += 1000;
$(this).attr("data-value", time).text(TimeToText(time));
}
});
}
The function TimeToText() simply takes a millisecond value and output it as hour:seconds (00:00).
The attribute data-value contains a millisecond value and is stores in the variable time.
This is my "debug" output:
var time = $(this).attr("data-value"); time = 4376
if (time > 0) { is true as 4376 is larger than 0
time += 1000; after this "time" is 43761000 - her it starts concatenating the text "4376" and "1000" and this is the proof that the JavaScript engine thinks time is a string type.
How do I make it clear that time should be an integer type?
var time = $(this).attr("data-value");
var timeInt = parseInt(time) + 1000;
You can use coercion trough the unary +, or just wrap it in a parseInt with a base of 10.
wallboard.data.Timer = function () {
$("div[data-value]").each(function () {
var time = parseInt($(this).attr("data-value"), 10);
if (time > 0) {
time += 1000;
$(this).attr("data-value", time).text(TimeToText(time));
}
});
}
Also, you could have searched for "javascript string to number" and you would find billions of results.
EDIT: Why not interpret numeric strings as numbers automatically? Because that would be a very unpleasant deviation from the convention: in JS you try to modify as little as possible your outputs. If you then wanted to actually concatenate two numeric strings together, you'd have to do lots of hacks to do it:
Instead of var a = "1000" + "10" to get "100010", you would have to do something like this
var a = ["1000", "zz10"].join(""); // note the "zz", so it's not plain numeric.
a = a.replace("zz", ""); // replace "zz" with nothing.
// now `a` would be "100010"
You need to convert the string retrieved with attr() into a number, e.g.
var time = +($(this).attr("data-value"));
You can use unary plus operator to convert the string attribute value to a number(you can also use parseInt())
var time = +$(this).attr("data-value");
You should convert the string to integer before adding it with 1000.
var time = parseInt($(this).attr("data-value"));

Categories

Resources