from api i get this strings:
"18% increased Area of Effect", "25% increased Area of Effect", "19% increased Area of Effect"
i want to make like this:
"(18%-25%) increased Area of Effect"
const filtredArray = array.filter((item) => item.implicit_mods);
let implicitsList = [];
filtredArray.forEach((item) => implicitsList.push(item.implicit_mods));
implicitsList.forEach((implisit) => {
if (implisit) {
implisit.forEach((implicit) => {
if (implicit) {
if (!/\d/.test(implicit)) {
//implicits without number
if (!uniqueImplicitMap.get(implicit)) {
addToMap(uniqueImplicitMap, implicit);
}
} else {
// implicits with number
let value = implicit.match(/\d+/g);
let replaceImplicit = implicit.replace(/\d+/g, '#');
if (value.length >= 2) {
addToMap(uniqueImplicitMap, replaceImplicit, [
value[0],
value[1],
]);
} else {
addToMap(uniqueImplicitMap, replaceImplicit, value);
}
}
}
});
}
});
}
function addToMap(map, key, value) {
if (!map.get(key)) {
if (value) {
map.set(key, [value, value]);
} else {
map.set(key);
}
}
if (map.get(key) && value) {
if (value[0] > map.get(key)[0]) {
map.get(key).splice(0, 1, value);
} else if (value < map.get(key)[0] && value < map.get(key)[1]) {
map.get(key).splice(1, 1, value);
}
}
}
i can do it if i have only one number in string
but if string like this:
"10% chance to gain Unholy Might for 3 seconds on Kill"
code break.
help me please
I do not completely understand your code. What I think you want is if you get a array of strings from the API like ["18% increased Area of Effect", "25% increased Area of Effect", "19% increased Area of Effect"], and you want to make that into (18%-25%) increased Area of Effect.
If so, you can just run a .map onto the array to find the percent with symbols, and get the percent. With that is is quite easy to generate a string with ES6 template literals.
Example Code
JS Fiddle for snippet.
// Select elements on HTML
const
before = document.querySelector(".previous"),
before2 = document.querySelector(".previous2"),
after = document.querySelector(".after"),
after2 = document.querySelector(".after2");
// Sample API text
const beforeText = ["18% increased Area of Effect", "25% increased Area of Effect", "19% increased Area of Effect"];
const before2Text = ["10% chance to gain Unholy Might for 3 seconds on Kill", "18% chance to gain Unholy Might for 3 seconds on Kill", "26% chance to gain Unholy Might for 3 seconds on Kill"];
// Display before paresed strings
before.innerText = beforeText.join(" -=- ");
before2.innerText = before2Text.join(" -=- ");
// Display parsed strings
after.innerText = parser(beforeText);
after2.innerText = parser(before2Text);
function parser(arrText) {
const PERCENT_REGEX = /[0-9]{1,2}%/;
// Get percents of strings.
const percents = arrText.map(elem => {
const percentStr = elem.match(PERCENT_REGEX)[0];
return parseInt(
// Remove percent symbol
percentStr.substring(0, percentStr.length - 1), 10
);
});
const chanceToDoWhat = arrText[0].replace(PERCENT_REGEX, "");
return `(${Math.min(...percents)}%-${Math.max(...percents)}%)${chanceToDoWhat}`;
}
Before Parse:<br>
<code class="previous"></code>
<br>
<br>
Before Parse 2:<br>
<code class="previous2"></code>
<br>
<br>
After Parse:<br>
<code class="after"></code>
<br>
<br>
After Parse 2:<br>
<code class="after2"></code>
Related
There is one project challenge on freecodecamp about building a calculator and I just managed to pass all the tests but when looking back on my code, the section dealing with the operations are barely readable. I've read some articles online regarding how to reduce the complexity of conditionals and the principles to keep in mind for more easy-to-understand logic.
However, figuring out the achievable logics for this task in javascript is quite challenging to me now. I was trying to meet two conditions with this section of code as follows:
User Story #13: If 2 or more operators are entered consecutively, the operation performed should be the last operator entered (excluding the negative (-) sign). For example, if 5 + * 7 = is entered, the result should be 35 (i.e. 5 * 7); if 5 * - 5 = is entered, the result should be -25 (i.e. 5 * (-5)).
User Story #14: Pressing an operator immediately following = should start a new calculation that operates on the result of the previous evaluation.
Here is the link to the page for this particular challenge and
this is the link to the code I wrote by far.
Is there any tips and advice on refining the code or other approaches for coping with this part?
handleOperation(event){
const {value}=event.target
const displayLength=this.state.display.length
const condition1=this.state.display=="+"||this.state.display=="-"||this.state.display=="×"||this.state.display=="÷"||this.state.display==""
const condition2=/^\d*\.?\d*$/.test(this.state.input)&&!/=/.test(this.state.display)
const condition3=this.state.input=="-"&&(this.state.display.charAt(displayLength-2)=="+"||this.state.display.charAt(displayLength-2)=="-"||this.state.display.charAt(displayLength-2)=="×"||this.state.display.charAt(displayLength-2)=="÷")
const condition4=this.state.input=="-"&&value=="-"&&!/=/.test(this.state.display)
const condition5=this.state.input=="-"&&value!=="-"&&!/=/.test(this.state.display)
const condition6=this.state.input!=="-"&&value!=="-"&&!/=/.test(this.state.display)
const condition7=this.state.input!=="-"&&value=="-"&&!/=/.test(this.state.display)
const condition8=/=/.test(this.state.display)
console.log(this.state.display.replace(/=/,"$'"))
if(condition1){
this.setState({
input:value,
display:value
})
}else if(condition2){
this.setState({
input:value,
display:this.state.display+value
})
}else if(condition3){
this.setState({
input:value,
display:this.state.display.replace(/[\+\-×÷]-$/,value)
})
}
else if(condition4){
this.setState({
input:value,
display:this.state.display.replace(/(?<=\d)-$/,"--")
})
}else if(condition5){
this.setState({
input:value,
display:this.state.display.replace(/(?<=\d)-/,value)
})
}else if(condition6){
this.setState({
input:value,
display:this.state.display.substring(0,displayLength-1)+value
})
}else if(condition7){
this.setState({
input:value,
display:this.state.display+value
})
} else if(condition8){
this.setState({
input:value,
display:this.state.display.substring(this.state.display.indexOf("=")+1)+value
})
}
}
Break down the process to the basic steps:
get the operation(s) from the string
get the numbers from the string
do the operation
Here's a snippet for this:
const calcs = [
"5 + 15",
"5 - 5",
"5 - - 5",
"5 / + 5",
"5 / - 5",
"5 / * + 5",
"5 / + * 5",
]
const container = document.getElementById("container");
// getting the operation(s) from the string
const getOperation = (calc) => {
const regex = /d*([+|\-|\*|\/]+)d*/g
const listOfOperations = calc.match(regex)
let operation = listOfOperations.pop()
let nextIsNegative = false
// if the operation is "-" and it wasn't the last item
if (listOfOperations.length && operation === "-") {
operation = listOfOperations.pop()
nextIsNegative = true
}
return {
operation,
nextIsNegative,
}
}
// getting the numbers from the string
const getNumbers = (calc) => {
const regex = /\d+/g
return calc.match(regex)
}
// doing the calculation
const doOperation = ({
operation,
nextIsNegative
}, [num1, num2]) => {
const operationObj = {
"+": (a, b) => a + b,
"-": (a, b) => a - b,
"*": (a, b) => a * b,
"/": (a, b) => a / b,
}
const n1 = Number(num1)
const n2 = nextIsNegative ? Number(num2) * -1 : Number(num2)
return operationObj[operation](n1, n2)
}
(function(calcs) {
const html = calcs.map((calc, i) => {
const operation = getOperation(calc)
const numbers = getNumbers(calc)
const result = doOperation(operation, numbers)
return `
<div id="in${i}">${calc}</div>
<div id="operation${i}">${JSON.stringify(operation)}</div>
<div id="result${i}">${ result }</div>`
})
container.innerHTML = html.join('')
})(calcs);
#container {
display: grid;
grid-template-columns: 80px 1fr 80px;
}
<div id="container"></div>
I'm currently programming a Discord bot, and was wondering if it is possible to predict the wanted command if the input was incorrect.
For example, I have this list of words :
['help','meme','ping'],
and if the user inputs "hepl", would it somehow be possible to "guess" they meant to type help ?
One option would be to find a command whose levenshtein distance from the input is 2 or less:
// https://gist.github.com/andrei-m/982927
const getEditDistance=function(t,n){if(0==t.length)return n.length;if(0==n.length)return t.length;var e,h,r=[];for(e=0;e<=n.length;e++)r[e]=[e];for(h=0;h<=t.length;h++)r[0][h]=h;for(e=1;e<=n.length;e++)for(h=1;h<=t.length;h++)n.charAt(e-1)==t.charAt(h-1)?r[e][h]=r[e-1][h-1]:r[e][h]=Math.min(r[e-1][h-1]+1,Math.min(r[e][h-1]+1,r[e-1][h]+1));return r[n.length][t.length]};
const commands = ['help','meme','ping'];
const getCommand = (input) => {
if (commands.includes(input)) return input;
return commands.find(command => getEditDistance(input, command) <= 2);
};
console.log(getCommand('hepl'));
(2 is just a number, feel free to pick the tolerance you want - the higher it is, the more commands will be guessed at, but the more false positives there will be)
You can find hits and show many words in suggestion. If you want same you can use to show most hit word.
const words = ["help", "meme", "ping"];
const getHits = (word, wordToMatch, hits = 0) => {
if (!word.length || !wordToMatch.length) return hits;
let charW = word.slice(0, 1);
let index = wordToMatch.indexOf(charW);
if (index !== -1) {
return getHits(
word.slice(1),
String(wordToMatch.slice(0, index) + wordToMatch.substr(index + 1)),
hits + 1
);
}
return getHits(word.slice(1), wordToMatch, hits);
};
const getMatch = mword => {
return words.reduce((m, word) => {
m[word] = getHits(mword, word);
return m;
}, {});
};
const sort = obj => {
return Object.entries(obj).sort(
([_, value1], [__, value2]) => value2 - value1
);
};
console.log(getMatch("help"));
console.log(sort(getMatch("help")));
console.log(getMatch("me"));
console.log(sort(getMatch("me")));
.as-console-row {color: blue!important}
I have been trying to come up with a solution for this algorithm for 3-4 days but nothing seems to work and the available solutions are a bit more advanced for me. It has to be solved with conditionals only so no recursion or dynamic programming.
I need to determine the least amount of coins necessary to give change given the following denominations: 1, 0.5, 0.2, 0.1, 0.05, 0.02 and 0.01.
Input is the following:
Price of an item
Sum paid by customer
Current ideas:
let price = +gets();
let paidSum = +gets();
//gets is used to accept number input
let change = paidSum - price;
I figured I could use Math.floor to isolate the integer part and subtract it but then I have no idea what to do with the remaining sum.
Would modulo work to test whether the remaining sum contains any of the remaining values for change and then subtract again until I reach zero?
I do realize this isn't the best formulated question but I am at a loss here and I've done every other task apart from this. Thanks.
Simpler, reverse and map the denominations in cents and return a new array with the number of coins you need for each denomination.
const coinsCents = [1, 2, 5, 10, 20, 50, 100]
const getChange = (amountInCents) => {
return coinsCents.reverse().map(coin => {
let amountCoin = Math.floor(amountInCents/coin)
amountInCents -= amountCoin * coin
return amountCoin
}).reverse()
}
With the denominations you have specified, the problem is simpler than the general change making problem. In this actual case we can be sure that using the largest denomination, that is not greater than the amount to pay, always leads to an optimal solution.
So then there is no need for recursion or dynamic programming. Just a simple loop will do.
I will here ignore the additional "layer" of getting the price of the bill and the amount that the customer pays. In the end the only thing that counts is the change amount to pay back to the customer. So this snippet asks for that change amount and returns the coins that need to be given as change.
function getChange(amount) {
amount *= 100; // Convert to number of cents
var denominations = [1, 2, 5, 10, 20, 50, 100]; // cents
var result = [];
while (amount > 0) {
var coin = denominations.pop(); // Get next greatest coin
var count = Math.floor(amount/coin); // See how many times I need that coin
amount -= count * coin; // Reduce the amount with that number of coins
if (count) result.push([coin/100, count]); // Store count & coin
}
return result;
}
// I/O management
change.oninput = function () {
var coins = getChange(this.value);
result.textContent = coins.map(([coin, count]) => `${count} x $${coin}`).join(" + ");
};
To be paid to customer: <input id="change">
<div>Coins to pay: <span id="result"></span></div>
var coins;
var coinArray = {};
var output = {};
/* Method to get coin value without decimal point - it is required because
* javascript will consider 5.6 as 6 if we do Math.round()
*/
function getRoundFigureCoinValue(x) {
return (x * 10 - ((x * 10) % 10)) / 10;
}
// Method to calculate possible combination of coins
function calculateCoins(input) {
let largestPossibleCoin = 1;
if (input) {
coins.forEach((x) => {
if (input >= x) {
largestPossibleCoin = x;
}
});
let remainingCents = input % largestPossibleCoin;
output[largestPossibleCoin] = getRoundFigureCoinValue(
(input / largestPossibleCoin).toFixed(1)
);
if (remainingCents && input > 1) {
calculateCoins(remainingCents);
}
return largestPossibleCoin;
}
}
// Method to be called to get output.
function calculatePossibleCoinCombinations(value) {
if (isNaN(value) || +value <= 0) {
console.log('Invalid input');
return;
} else {
console.log('Possible combinations are:')
value = +value;
}
coins = [1, 5, 10, 25];
while (coins.length) {
let largestPossibleCoin = calculateCoins(value) || 0;
let outputString = '';
coins = coins.filter((x) => x < largestPossibleCoin);
Object.keys(output).forEach((key) => {
outputString += `${output[key]} - ${key} cents; `;
})
console.log(outputString);
output = {};
}
}
/*
Sample inputs:
calculatePossibleCoinCombinations('89');
calculatePossibleCoinCombinations(10);
calculatePossibleCoinCombinations(0);
calculatePossibleCoinCombinations('someString');
calculatePossibleCoinCombinations(-10)
*/
I implemented the way to generate a list of items with iterable counts with prefix 0. What is the best way to generate such kind of list?
Current behaviour:
const generateList = (length, n, i) => {
let b = n+i
return b.toString().padStart(length.toString().length + n.toString.length, 0)
}
Array(10).fill(null).map((x, i) => generateList(10,2, i))
Output result:
["002", "003", "004", "005", "006", "007", "008", "009", "010", "011"]
Do u have any idea to make it another way?
You could determine the number of characters needed at the start and used the predetermined value to format the output for the array.
function createList(startValue, endValue) {
let
// The minimum output length, for a single digit number, is 2 chars.
outputLength = 2,
testValue = 10,
// Create an empty array which has as many items as numbers we need to
// generate for the output. Add 1 to the end value as this is to be
// inclusive of the range to create. If the +1 is not done the resulting
// array is 1 item too small.
emptyArray = Array(endValue - startValue + 1);
// As long as test value is less than the end value, keep increasing the
// output size by 1 and continue to the next multiple of 10.
while (testValue <= endValue) {
outputLength++;
testValue = testValue * 10;
}
// Create a new array, with the same length as the empty array created
// earlier. For each position place a padded number into the output array.
return Array.from(emptyArray, (currentValue, index) => {
// Pad the current value to the determined max length.
return (startValue + index).toString().padStart(outputLength, '0');
});
}
function createListWithLength(length, startValue = 0) {
return createList(startValue, startValue + length);
}
console.log(createList(2,10));
console.log(createListWithLength(30));
console.log(createListWithLength(10, 995));
Have a look at generators:
function* range(from, to) {
for (var i=from; i<to; i++)
yield i;
}
function* paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
for (const i of range(from, to))
yield i.padStart(length, '0');
}
console.log(Array.from(paddedRange(2, 12)));
You can also inline the loop from range into paddedRange, or you can make it return an array directly:
function paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
return Array.from(range(from, to), i => i.padStart(length, '0'));
}
console.log(paddedRange(2, 12));
The main simplification is that you should compute the padding length only once and give it a denotative name, instead of computing it for every number again. Also ranges are usually given by their lower and upper end instead of their begin and a length, but you can easily switch back if you need the latter for some reason.
Not sure, but maybe something like this
const generateList = length => Array(length).fill('0').map((item, index) => item + index);
console.log(generateList(20));
I wrote a script with the purpose of sequencing the Fibonacci Sequence (or any two numbers that would add to make the next, and then those two, etc.). When you press a button, the function (called fibonacci) adds the two values together, pushes the new value into an array (called sequence), and then displays the most recent value in the array. I set it up with a setInterval (called recursion), so it continues to add more values to the array, and display more numbers. I was experimenting with the function, and thought to try two strings instead of two numbers. It worked as expected, however it slowed down significantly, crashing the browser within the span of five seconds. I was wondering what the difference would be, performance-wise, between numbers and strings.
My jsfiddle is here: https://jsfiddle.net/MCBlastoise/yrr7fL4z/54/
And here is my code:
var sequence = [0, 1];
var i = 2;
function recursion() {
recur = setInterval(fibonacci, 1);
}
function fibonacci() {
var current = document.getElementById("text");
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
if (current.innerHTML === "") {
current.innerHTML = sequence[0] + ", " + sequence[1] + ", " + sequence[2];
}
else {
current.innerHTML = current.innerHTML + ", " + sequence[i];
}
i++;
};
function exactValue(position) {
var current = document.getElementById("text");
if (isNaN(position) === false && position % 1 === 0 && position >= 1) {
if (position === 1) {
current.innerHTML = sequence[0];
}
else if (position === 2) {
current.innerHTML = sequence[1];
}
else {
while (i !== position) {
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
i++;
}
if (i === position) {
current.innerHTML = "The value at position " + position + " is " + a + ".";
}
}
}
}
function checkValue(value) {
var current = document.getElementById("text");
if (isNaN(value) === false) {
if (value === 0) {
current.innerHTML = "The value provided appears at position " + 1 + ".";
}
else if (value === 1) {
current.innerHTML = "The value provided appears at position " + 2 + ".";
}
else {
while(a !== value && a !== Infinity) {
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
i++;
}
if (a === value) {
current.innerHTML = "The value provided appears at position " + i + ".";
return true;
}
if (a === Infinity) {
current.innerHTML = "The value provided does not appear in this sequence.";
return false;
}
}
}
}
function clear() {
document.getElementById("text").innerHTML = "";
}
<div onclick="recursion(), clear()" style="cursor:pointer; background-color:black; width:30px; height:30px"></div>
<p id="text"></p>
When you change the elements of the sequence array to be strings, the + operator in the following line will perform a completely different operation:
var a = sequence[i-2] + sequence[i-1];
Instead of an arithmetic addition, this will be a string concatenation operation. This will involve a lot more memory and CPU time:
Addition of two numbers:
Time: constant, since an addition is performed as a CPU instruction, limited to the 64-bit float range.
Memory: one 64-bit float, since that is how numbers are represented in JavaScript.
Concatenation of two strings:
Time: linear in terms of the length of the input strings: each character from both strings needs to be copied to a new memory location
Memory: doubles, as the final string occupies the same memory as the two input strings together
The memory impact will probably be the factor that kills the script: after only 20 iterations (i.e. calls to fibonacci) the string value of a will have a length of over 10 000 characters, which will continue to almost double each next iteration. After 30 iterations, a will have more than a million characters. If you have enough patience to wait for the string copying of those megabytes to grow to gigabytes you'll find your PC's memory (the part available to the JavaScript box) has been eaten completely, probably before the 40th iteration.
Well, loading numbers into memory and adding them can usually be compiled to just a few native CPU instructions, while concatenating Strings usually includes a lot of function calls through the whole language to produce a result. And I'm not sure how JavaScript handles strings internally, but growing a string could mean allocating a whole new byte array for each one.