Calling array values based on DOM return - javascript

Return a string based on pulled dom elements
I have an object storing months and their index (not dates) monthList = {"jan" : "1", "feb" : "2". etc: etc}
The user can type something like jan or jan,feb,march and I want a string returned as 1 or 1,2,3 (which I use for a get call elsewhere) but haven't been able to do this, ive tried using all sorts of crazy loops to no avail, from incorrect reading to always reading last index, if the user inputs 1,2,3 that should also work.
The input values as simply called using ${document.getElementById('monthInput').value}
User Input Example #1: jan,feb,dec
User Input Output #1: 1,2,12
User Input Example #2: 1,2,5
User Input Output #2: 1,2,5
How can I do this?

I admit to not understanding why you would accept user input in such odd formats. The only way to transform user input that matches no specific syntax/format is to use a manually created matrix.
In the inputMap below you would need to list each user input and the string value that it should be translated to:
const inputMap = {
"jan": "1",
"feb": "2",
"march": "3",
1: "1",
2: "2",
3: "3",
"dec": 12,
5: "5"
}
const input1 = "jan,feb,dec"
const input2 = "1,2,5"
const mapInput = inputString => inputString.split(",").map(i => inputMap[i]).join(",")
console.log(mapInput(input1))
console.log(mapInput(input2))

According to this answer, you can recursively use Date to accomplish this, given input months:
months.split(",").map((month) => {
return (isNaN(month) ? new Date(Date.parse(month +" 1, 2019")).getMonth()+1 : month)
}).join(",")
This function iterates over each code/number string using map, checks whether or not the a given string is not number using isNaN() in a ternary operator, and accordingly returns the given number/converted code.

You can do this a few ways:
Using a simple for..of loop
Using .replace() (keeps the formatting of original string)
Using a mapping method (using: .map)
Going overboard with recursion + ternaries...
Using Loops:
const months = {jan:"1",feb:"2",mar:"3",apr:"4",may:"5",jun:"6",jul:"7",aug:"8",sep:"9",oct:"10",nov:"11",dec:"12"};
const input = "jan,dec,feb";
const dates = input.split(','); // turn your input into an array
let converted = "";
for(let month of dates) { // loop through each month in dates
if(month in months) { // check if the month is a key in months
converted += months[month] +','; // add number version to converted sring
} else { // if the month isn't in the converted month object, then no need to convert it
converted += month+','; // add month to (ie the number) to the converted output
}
}
console.log(converted.slice(0, -1)); // using slice(0, -1) to remove trailing comma
Using .replace() to keep original formatting:
const months = {jan:"1",feb:"2",mar:"3",apr:"4",may:"5",jun:"6",jul:"7",aug:"8",sep:"9",oct:"10",nov:"11",dec:"12"};
let input = "jan, dec, feb, 5";
const dates = input.split(','); // turn your input into an array
for(let month of dates) {
month = month.trim();
if(month in months) {
input = input.replace(month, months[month]);
}
}
console.log(input);
Using map. Here the inner arrow function is called for each month, and then converted to its associated value in the months object. We then use .join(',') to join the array of values:
const months = {jan:"1",feb:"2",mar:"3",apr:"4",may:"5",jun:"6",jul:"7",aug:"8",sep:"9",oct:"10",nov:"11",dec:"12"};
const input = "jan,dec,feb";
const converted = input.split(',')
.map((month) => months[month] || month)
.join(',');
console.log(converted);
Using recursion with the ternary operator:
const months={jan:"1",feb:"2",mar:"3",apr:"4",may:"5",jun:"6",jul:"7",aug:"8",sep:"9",oct:"10",nov:"11",dec:"12"};
const input = "jan,dec,feb";
const res = (f = ([m, ...rest]) => m && m in months ? months[m]+','+f(rest) : m ? m+','+f(rest) : '')(input.split(',')).slice(0,-1);
console.log(res);

Related

TypeScript: How to replace a particular number in a string (a combination of numerical and non-numerical values), and then update its value?

I asked a similar question here TypeScript: How to replace a particular number in a string, and then update its value?
Really appreciate the answers there. It answered my questions.
I am run into a new issue. Thought it s more helpful to raise a new question while referring to the old question.
I have a column that is full of 10-digits string.
Sometimes that entire 10-digits only contain numerical values (e.g. 3345678901), but sometimes there is dash included (e.g. 3345678---)
I would like to be able to:
Input an index number X
Locate the corresponding number in the string
Add or subtract a particular number A to/from that number to update the string
Update the string
Example 1 (all numerical): 3345678901
Input index number "4"
The corresponding number is 6
Increase that number by +2 to 8
Update the string to 3345878901
Example 2 (numerical & non-numerical): 3345678---
Input index number "4"
The corresponding number is 6
Increase that number by +2 to 8
Update the string to 3345878---
Example 3 (numerical & non-numerical): 3345678---
Input index number "7"
The corresponding value is -
Increase (or rather, update) that number by +2 to 2
Update the string to 33458782--
For example 1, I know I could do following (as a contributor from the OG post has pointed out):
const givenStr = "3345678901";
let givenStrArray = givenStr.split('').map(Number);
const inputIndex = 4;
const increaseAmount = 2;
givenStrNumber += increaseAmount
console.log(givenStrNumber);
But, how do I go about Example 2 and 3 though? Since there are string '-' involved? In this case map(Number) would lead to Null values that would break the code.
Any help would be greatly appreciated!
Check for NaN. This is a tiny snippet that would give you a hint:
// ...
// ...
const increment = 2;
let givenStrArray =
givenStr
.split('')
.map((digiit) => isNaN(digit) ? increment : Number(digit + increment);
// ...
// ...
Here's a simple little snippet. Break the sting apart, map through each item, when we find the index we need to update we update it and return it, then join them all back together.
Multiple conditional ternary operator have been used here, you can find out more about how they work here: Conditional (ternary) operator
const givenStr = "334567----",
inputIndex = 6,
increaseAmount = 2
let givenNumber = givenStr
.split('')
.map((v,i) => i === inputIndex ? isNaN(v) ? increaseAmount : +v + increaseAmount : v)
.join('')
console.log(givenNumber);
This should do the trick
let str = '3345678---'
let NumericStrArray = str.split('').map(x => Number.isNaN(Number(x)) ? x: Number(x))
let ipIndex = 7
let incAmount = 2
let val = NumericStrArray[ipIndex]
NumericStrArray[ipIndex] = typeof val === 'string' ? incAmount : val + incAmount
let result = NumericStrArray.join('')

Efficient way to check whether a month&year of date is present in list of dates

I want to check whether value : 30-08-2019 is present in array :['30-08-2019','25-09-2019','03-12-2019'].
This I could achieve by comparing the dates.
function isInArray(array, value): boolean {
return !!array.find(item => { return item.getTime() == value.getTime() });
}
But if my input date is 31-08-2019,then also the output should be true.
But if it is 31-08-2020, then the output should be false.
So, The check should be on the month and year and not the day.
Any help would be appreciated.
If you want to just check the month and the year, and if you can be sure that there are leading zeroes in all dates, you can simply use a substring of the date; cut off the initial three characters, which are the day and the hyphen.
If the leading zero might be omitted, you can split the string into components on the hyphen, and compare the second and third element of the resulting array instead.
You could for example do something along these lines:
let array = ["30-08-2019", "25-09-2019", "03-12-2019"];
const isMatch = (date) => array.some((e) => e.match(date.slice(2)));
console.log(isMatch("30-08-2019")); // true
console.log(isMatch("31-08-2019")); // true
console.log(isMatch("31-08-2020")); // false
You can compare month and year like that:
function isInArray(array, value): boolean {
return !!array.find(item => { return ((item.getMonth() == value.getMonth())&&( item.getYear() == value.getYear())) });
}

Iterating the days of the week

I have this piece of code which iterates a chosen set of days and should ring true if today is part of the chosen set. However, isDay rings false regardless of the daysChosen or what today happens to be. So what am I missing here?..
var date = new Date;
var isDay;
var today=date.toString().substring(0,4)
//console.log(today)//good
for (var daysChosen of ['Sun','Mon','Tue','Wed','Thu'])
{
console.log(daysChosen)//good
isDay = today==daysChosen ? true : false
}
console.log(isDay)//bad, should be true if today is part of daysChosen
Update:
Ok, this is some BULL ****!!!... how on earth can this evaluate to true given that today is in the array!?...
for (var value of ['Sun','Mon','Tue','Wed','Thu','Fri'])
{
var _day = (today!=value) ? true : false
break;
}
console.log(_day)
You have a few major problems that are causing you issues in your code.
var today=date.toString().substring(0,4) - The days are 3 characters long, so your getting the extra space at the end. today === "Sun ", notice the extra space.
Your not breaking out of your loops once you find the correct value as other answers have pointed out.
You can simply use the indexOf method. It returns the index of the given string or -1 if its not contained in the array.
var date = new Date();
// first 3 characters from string for day of week
var today = date.toString().substring(0,3);
var days = ['Sun','Mon','Tue','Wed','Thu'];
var isInDays = days.indexOf(today) > 0; // indexOf returns -1 if not contained
Or to fix your existing code:
var date = new Date;
var isDay;
var today=date.toString().substring(0,3)
//console.log(today)//good
for (var daysChosen of ['Sun','Mon','Tue','Wed','Thu'])
{
console.log(daysChosen)//good
isDay = today==daysChosen ? true : false
if(isDay) break; // must break once you find it or you will keep overriding the value.
}
Your loop continue looping when isDay becomes true and in the next iterations could assign false to it. You could use break statement to exit loop:
var isDay = false;
for (var daysChosen of ['Sun','Mon','Tue','Wed','Thu'])
{
if (today == daysChosen) {
isDay = true;
break;
}
}
You can also use Array.prototype.find() function to check if array contains today. (!! is double negation):
var isDay = !!['Sun','Mon','Tue','Wed','Thu'].find(function(day) {
return day === today;
})
Unfortunately find is not compatible with all browsers.
If you have an array of things and want to check if it has something, I would use the new .includes() property on arrays:
["Sun", "Mon", "Tue", "Wed", "Thu"].includes(today);
Also, instead of extracting the day of the week from the string output, use Date.prototype.getDay().
If you don't want to include the polyfill, you can use this trick I learned from Codegolf.SE:
~["Sun", "Mon", "Tue", "Wed", "Thu"].indexOf(today);
The ~ is a binary NOT operator, which will transform the bits in a data type to their opposite. The binary NOT of -1, which is returned from .indexOf() when there are no instances of the search term, is 0. In JavaScript there's a concept called coercion, which means that when there's typal dissonance, like adding booleans, for example, there are values of one type that will convert to another. For example, all numbers that are not zero are coerced to true, and 0 coerces to false. Becuase of this, if you put the above text into an if statement, it will act as if it is an .includes().
A better way
You're extracting the day of the week from the Date.toString(), which is not good practice. Consider using array access and Date.prototype.getDay() to make the process a lot more logical:
let today = new Date().getDay();
// Sun., Mon., Tue., etc.
if ([true, true, true, true, true, false, false][today]) {
// Day is matched
} else {
// Day is not matched
}
This has some advantages
Ultimate Customizability. You can specify exactly which days you want to match
Doesn't rely on strings. Your method of extracting from the string is going to get tripped up in non-English user agents, becuase their Date Strings will be different.

Group nearby dates together

I have a list of variable dates that I would like to group together, preferably in javascript.
ie.
2014-08-12
2014-08-10
2014-07-28
2014-07-27
2014-01-27
2013-04-27
2003-02-12
This list of days can be completely dynamic, but here is an example resultset.
Can anyone think of an elegant way to group dates that are considered to be 'near' each other together, which in this case would be:
2014-08-12
2014-08-10
2014-07-28
2014-07-27
2014-01-27
2013-04-27
2003-02-12
A way to do this is:
Convert all date strings to numbers using .getTime()
Sort
Group
Convert back to date string
An example of this:
var dates = ['2014-08-12', '2014-08-10', '2014-07-28', '2014-07-27', '2014-01-27', '2013-04-27', '2003-02-12'],
groups = [],
last = 0
dates.map(function (each) {
return new Date(each).getTime() // 1.
}).sort(function (a, b) {
return b-a // 2.
}).forEach(function (each) {
if (Math.abs(each-last) > 1e10) { // 1e10 ms = 116 days
groups.push([]) // 3.
}
groups[groups.length-1].push(each)
last = each
})
groups.map(function (dates) {
return dates.map(function (each) {
return new Date(each).toISOString().substr(0, 10) // 4.
}).join('\n')
}).join('\n\n')
You can adjust the 1e10 value to whatever nearby dates means to your application

Regex inside TableSorter parser deletes indices where the same regex works correctly in a separate console function

Using Jquery TableSorter, I am creating a custom parser to sort elapsed time <td>s that contain "'#' year(s) * '#' month(s)". When I use the function
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
console.log(match);
});
from the command line, each index contains an array of length 5, looking like this:
["7 months", "7", "months", undefined, undefined]
to this:
["3 years 3 months", "3", "years", "3", "months"]
depending on whether or not the elapsed time has just a month or year element, and then the other. To parse the text, I use regex to gather each element, and then use JS to test whether there are multiple elements or not, and if 1 element only, then wheher it begins with "y" or "m", and return the number of months, so the parser can sort the <td>s by number of months in integer form.
The parser passes in each element into the function as parameter "s". when i try regex on "s" directly, it is not returning an array of length 5, it is truncating it to 3 (whether or not I am running the line that truncates it if index 3 is typeof 'undefined'). When I use the console to directly use this function:
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
if (typeof match[3] == 'undefined') {match.length = 3;};
console.log(match);
});
the regex returns the arrays properly, with the array truncated if it only has 1 element (year or month). Here is the code for the custom parser:
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
console.log(match);
if (typeof match[3] == 'undefined') {match.length = 3;};
// 1 element case:
// month
if (match.length = 3) {
if (match[2][0] == "m") {
order.push(match[1]);
}
// year
if (match[2][0] == "y") {
order.push(match[1]*12);
}
// both elements
} else {
order.push(match[1]*12 + match[3]);
}
s = order;
return s;
},
The fiddle is here. The Elapsed parser is second from the bottom of the JS panel. As you can see, since I can't get the months from the array (indices 4 and 5), I can not calculate the months, and thus the sorting only incorporates years, and the months are sorted by their original HTML placement. What am I missing? (I'm learning.... so direction is appreciated more than an fix, but I won't turn it down.)
Yes I realize the JS fiddle is loaded (first part is TableSorter, to maintain functionality for verification(click on headers to sort), but all you need to focus on is the last part of the code (reference the '//Table Sorter dateSorter' to see how a correct parser should look). The section '//Table Sorter elapsedSorter' is where my two attempts are, the first part is the working code I use in the console, and the seconde part is the parser, which is somehow deleting the last two indices in the array, thus loosing the month information to calculate.
Guess I'll have to add Regex, and a personal rating of 1, since I've wasted almost an entire day on this.
if (match.length = 3) {
You meant this?
if (match.length == 3) {
To help you further, when you write conditions with one constant and a variable, you can write them like this instead:
if (3 = match.length) {
This would now cause a JavaScript error instead of silently getting turned into an assignment that always yields true.
In JavaScript, 12 + '4' == '124', so you have to be careful with numbers and the + operator. In languages such as PHP you don't have this problem, because they have an operator for string concatenations ;-)
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
if (typeof match[3] == 'undefined') {
if (match[2][0] == "m") {
order.push(parseInt(match[1]));
}
// year
if (match[2][0] == "y") {
order.push(parseInt(match[1])*12);
}
// both elements
} else {
order.push(parseInt(match[1])*12 + parseInt(match[3]));
}
s = order;
return s;
Btw use parseInt(x, 10) if you expect fields to have leading zeroes (which would otherwise result in 0 being returned). Thanks fudgey!

Categories