How to join strings conditionally without using let in javascript - javascript

I have a situation where I'm trying to join the array of strings only if it has a value. I did using let variable, but I wonder can I do this using map. I'm very mindful on the position, so I used in this way.
const [hours, minutes, seconds] =["", "10", ""]
let time = "";
if (hours) {
time += `${hours}h `;
}
if (minutes) {
time += `${minutes}m `;
}
if (seconds) {
time += `${seconds}s`;
}
console.log(time)
Will I be able to do this using map, filter and join?

If you put the hours, minutes, and seconds back into an array, you can make another array for the suffixes, add the suffixes by mapping the values, then filter out the resulting substrings that are 1 character or less (which would indicate that there wasn't a corresponding value).
const suffixes = ['h', 'm', 's'];
const [hours, minutes, seconds] = ["", "10", ""]; // combine this with the next line if you can
const hms = [hours, minutes, seconds];
const time = hms
.map((value, i) => value + suffixes[i])
.filter(substr => substr.length > 1)
.join(' ');
console.log(time)

Here's a nice little snippet
const suffixs = "hms"; // String arrays of single characters can be shortened to this!
const values = ["","10",""];
var string = values
.map((x,i) => x ? x + suffixs[i] : x)
.filter(x => x)
.join(" ");
console.log(string);
// Or if you want to have 0 in place of empty values
var string2 = values
.map((x,i) => (x || "0") + suffixs[i])
.join(" ");
console.log(string2);

Personally, I would create a list of objects, that represents the time.
I prefer this over using two arrays, as it can save some bugs (like changing the order of the data in one list but not in the other one):
const [hours, minutes, seconds] = ["20", "10", ""];
const time = [
{ amount: hours, sign: "h" },
{ amount: minutes, sign: "m" },
{ amount: seconds, sign: "s" },
];
const str = time
.filter((val) => val.amount)
.map((val) => val.amount + val.sign)
.join(" ");
console.log(str);

Related

Finding performance feasibility using array strings

Here is the requirement details:
time = ["09-13", "12-14"]
getResult(time) = false
The first performance runs from 9 a.m. to 1 p.m. and the second one starts at 12 p.m. So you won't be able to see each performance in full.
time = ["07-09", "10-12", "15-19"]
getResult(time) = true
but i could not able to get the result. I am finding challange to get it done. any one help me?
here is my try:
const getResult = (time) => {
const nums = [];
let pre = 0;
time.map((item,index) => {
item.split('-').map((v,i) => {
nums.push(+v);//converting as number
});
});
const result = nums.map((v,i) => {
if(!i) return;
console.log(v-pre)//but logically this is not works
pre = v;
})
}
//time = ["09-13", "12-14"]; //false
time = ["07-09", "10-12", "15-19"] //true
getResult(time); //should be false
Thanks in advance.
Your format is already useful for direct >= comparisons, once we split the values on their -'s. So we can simply sort the values, then check that in every case after the first one, that the start portion (before the -) is at least as large as the end portion (after the -) of the previous value. It could look like this:
const feasible = (times) => [... times]
.sort ()
.every ((t, i, a) => i == 0 || t .split ('-') [0] >= a [i - 1] .split ('-') [1])
console .log (feasible (["09-13", "12-14"]))
console .log (feasible (["07-09", "10-12", "15-19"]))
We use the i == 0 || to simply avoid testing the first of the sorted values.
This involves splitting each of the values twice (well, except the first one.) If this inefficiency bothers you, we could solve it (using more memory; there's always a tradeoff!) by splitting them and saving the result:
const feasible = (times) => [... times]
.sort ()
.map (s => s .split ('-'))
.every ((t, i, a) => i == 0 || t [0] >= a [i - 1] [1])
Turn each range into each individual hour within the range, then:
if the hour already exists in the array, return false
else, push to the array
const getResult = (ranges) => {
const filled = [];
for (const range of ranges) {
let [start, end] = range.split('-').map(Number);
while (end !== start) { // Exclusive
if (filled.includes(start)) return false;
filled.push(start);
start++;
}
}
return true;
};
console.log(getResult(["09-13", "12-14"]));
console.log(getResult(["07-09", "10-12", "15-19"]));
Your current approach doesn't look to have any notion of turning the ranges into their individual hours, or of identifying overlaps.
Sort the time slots based on their start time.
Loop over all the time slots in the sorted array and if anytime the start of a slot is less than the end of the previous one, then return false.
If the whole loop is exhausted return true.
function isValid(time) {
const sortedTime = [...time].sort((a, b) => {
const slotA = Number(a.split("-")[0]);
const slotB = Number(b.split("-")[0]);
return slotA - slotB;
});
let last;
for (let t of sortedTime) {
const [start, end] = t.split("-").map(Number);
if (last && start < last) {
return false;
}
last = end;
}
return true;
}
console.log(isValid(["12-14", "09-13"]));
console.log(isValid(["10-12", "07-09", "15-19"]));

Javascript - Regex replace number with HH:MM

I am trying to replace 4 numbers with a time format. For example if user enters 1234 to be replaced with 12:34
I have found that this regex does this job
let myString = "1234";
myString.replace(/\b(\d{2})(\d{2})/g, '$1:$2')
But now I am trying to figure out how to use this with cases like
94 - this should be replaced with 23 then it does same for time after the colon
01:74 - this should be replaced with 01:59
I have found a regex which does that ^([0-1]?[0-9]|2[0-3]):[0-5][0-9], but I am not able to figure out how to combine this with .replace
You will need to match on the first and second pair of digits and then bound them by their max values. Once you have the bounded values, you can pad the numbers and join them with a colon.
const toTimeString = (value) => {
const
[, hours, minutes] = value.match(/^(\d{2})(\d{2})$/),
hour = `${Math.min(+hours, 24)}`.padStart(2, '0'),
minute = `${Math.min(+minutes, 59)}`.padStart(2, '0');
return `${hour}:${minute}`;
};
console.log(toTimeString('0174')); // 01:59
console.log(toTimeString('3412')); // 24:12
Now, here is a replacer example:
const minPad = (value, min) => `${Math.min(value, min)}`.padStart(2, '0');
const toTimeString = (value) =>
value.replace(/\b(\d{2})(\d{2})\b/g, (match, hours, minutes) =>
`${minPad(hours, 24)}:${minPad(minutes, 59)}`);
console.log(toTimeString('0174 3412')); // 01:59 24:12
There is an overload of replace which takes a function which you can use to do any logic you need, such as:
let myString = "1234";
function formatTime(input){
return input.replace(/\b(\d{2})(\d{2})/, (_,hh,mm) => {
return `${Math.min(hh,24)}:${Math.min(mm,59)}`
})
}
console.log(formatTime("1234"));
console.log(formatTime("3412"));
console.log(formatTime("0174"));
I do not see any good reason to use regex in your case.
Just a simple function will do the job.
function transformTextToHHMMTimeFormat(text) {
const firstNumber = Number(text.slice(0, 2))
const secondNumber = Number(text.slice(2, 4))
const hour = Math.min(firstNumber, 24)
const minute = Math.min(secondNumber, 59)
return `${hour}:${minute}`
}

convert array with strings of minute format to seconds format

["4", "5.67", "1:45.67", "4:43.45"]
I have this string array and i want to convert all of the strings to numbers with seconds format so it will become something like this
[4, 5.67, 105.67, 283.45]
how can i do it?
function hmsToSecondsOnly(str) {
var p = str.split(':'),
s = 0, m = 1;
while (p.length > 0) {
s += m * parseInt(p.pop(), 10);
m *= 60;
}
return s;
}
I found this but it seems to only work in MM:SS format like 1:40 but i want convert strings in x:xx.xx format
You can try using map() like the following way:
var data = ["4", "5.67", "1:45.67", "4:43.45"];
data = data.map(function(item){
//split to get the hour
var a1 = item.split(':');
//split to get the seconds
var a2 = item.split('.');
//check the length
if(a1.length > 1){
//split to get minutes
var t = a1[1].split('.');
//calculate, cast and return
return +((a1[0]*60 + +t[0]) + '.' + a2[a2.length - 1]);
}
else return +item;
});
console.log(data);
You could map the formatted time values.
const
data = ["4", "5.67", "1:45.67", "4:43.45"],
result = data.map(time => time
.split(':')
.map(Number)
.reduce((m, s) => m * 60 + s)
);
console.log(result);
Another simple solution with RegEx.
const input = ["4", "5.67", "1:45.67", "4:43.45"]
const result = input.map(ele => ele.replace(/^(\d+):(\d+[.]\d*)$/, (m, g1, g2) => `${g1 * 60 + parseFloat(g2)}`));
console.log(result)

Is there an easier way to split "134h22m54s"? [duplicate]

This question already has answers here:
regular expression to match days hours minutes
(5 answers)
Closed 2 years ago.
I'm getting data like "134h22m54s" from an API. With a function I created, it returns as an object includes hours, minutes and seconds.
Here my split function:
parseHMS (value) { // value = "134h22m54s" or "3m0s" or only "0s"
let hour = "0";
let minute = "0";
let second = "0";
if (value.includes('h')) {
let splitByHour = value.split('h');
hour = splitByHour[0]
value = splitByHour[1];
}
if (value.includes('m')) {
let splitByHour = value.split('m');
minute = splitByHour[0]
value = splitByHour[1];
}
if (value.includes('s')) {
let splitByHour = value.split('s');
minute = splitByHour[0]
}
return {h: hour, m: minute, s: second}
}
And the output:
{
h: "134",
m: "22",
s: "54"
}
I would like to know if there is an easier way to parse this type of data.
You can use Regex:
function parseDuration(s) {
var m = /(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m?)?/.exec(s);
return {
days: parseInt(m[1], 10) || 0,
hours: parseInt(m[2], 10) || 0,
minutes: parseInt(m[3], 10) || 0
};
}
console.log(parseDuration('10d12h59m'));
console.log(parseDuration('10d12h'));
console.log(parseDuration('10d'));
console.log(parseDuration('12h'));
console.log(parseDuration('70'));
As a simple but not bulletproof solution you can split your string by numeric characters and filter only numbers.
const [h,m,s] = "134h22m54s".split(/(\d+)/).filter(Number);
console.log(h,m,s);
I would recommend using a regular expression here. This can selectively match parts of a string (i.e. it may or may not be there) using non-capturing groups with a quantifier.
let parseHMS = (value) => {
let reg = /(?:(?:(\d+)h)?(?:(\d+)m)?)?(\d+)s/
let result = reg.exec(value)
return {h: result[1], m: result[2], s: result[3]}
}
Explanation on regex101
You can improve it, but maybe something like this with regex:
const parseHMS = (value) => {
let reg = /((\d+)h)?((\d+)m)?((\d+)s)/
let result = reg.exec(value)
return {h: result[2], m: result[4], s: result[6]}
}

Sum strings that have an optional slash in them

I need to sum all of the values in an array of strings, some of which are empty, some are normal integers, some are separated by slashes. I have it working when the values are just integers or empty, but not when they are separated by slashes.
//this works and should total 30
//var data = ["","1","","2","3","10","14"];
//this doesn't work and should total 166, not 128
var data = ["","1","2","5 / 35","","100 / 3", "20"];
var sum = data.reduce(function (a, b) {
a = parseInt(a, 10);
if(isNaN(a)){ a = 0; }
b = parseInt(b, 10);
if(isNaN(b)){ b = 0; }
return a + b;
});
console.log(sum);
Here is a codepen with the example...
https://codepen.io/murphydan/pen/GGWwgE?editors=0011
I suppose you simply want to sum all numbers in the array, no matter what's the elements content (as your desired result is 166). You can simply split and use another reduce
const data = ["", "1", "2", "5 / 35", "", "100 / 3", "20"];
const res = data.reduce((a, b) => {
const t = b.split('/');
return a + t.reduce((x, y) => x + Number(y), 0);
}, 0);
console.log(res);
If you need it even more flexible, for example if the slash could also be something else, like a comma, dash or whatever, you could split by non digits too. split(/\D/). This will create some more array entries as every whitespace gets another entry, but that doesn't change the result.
I like to avoid nesting functions like .reduce().
Like:
const data = ["", "1", "2", "5 / 35", "", "100 / 3", "20"];
const res = data.join(' ')// to a single string
.replace(/\//g, '')// replace all slashes
.split(/\s/)// split on whitespace to array
.reduce((acc, n) => (acc + (parseInt(n) || 0)) ,0);// sum all numbers
console.log(res);

Categories