Display one digit percentage, skip fixed numbers vue - javascript

I have a function that rounds each percentage to 1:
items() {
return this.data
.map(item => {
const perc= item.count/ number * 100
const percentage = parseFloat(perc).toFixed(1) + '%'
return { ...item, percentage }
})
.sort((a, b) => b.count - a.count)
}
But the problem is that it rounds also the fixed numbers. For example:
100% => 100.0% -> issue
So how can I fix this?

Just check if it is a whole number before you round:
const vals = [0,1,1.1,1.1234, 100.0, 100]
const toPercentage = (x) => ((x|0) === x ? String(x) : x.toFixed(1)) + '%'
console.log(vals.map(toPercentage))
Try something like this:
sortedItems () {
return this.data
.map(item => {
const perc = item.count/ this.smsData.number * 100
const percentage = ((perc|0) === perc ? String(perc) : perc.toFixed(1)) + '%'
return { ...item, percentage }
})
.sort((a, b) => b.count - a.count)
}
(Note that perc already is a number, so you don't need parseFloat()

You can easily achieve it with numeraljs
numeral(1).format('0.[0]%') // '100%'
numeral(0.1).format('0.[0]%') // '10%'
numeral(0.56).format('0.[0]%') // '56%'
So your code will look like this
sortedItems () {
return this.data
.map(item => {
const percentage = numeral(item.count/this.smsData.number).format('0.[0]%')
return { ...item, percentage }
})
.sort((a, b) => b.count - a.count)
}

Related

Why is this attempt to retrieve the minimum number of an array not working?

Max should be = 9.99, and min should be = 6.88
let arr = [["2019","00","01", 9.99], ["2018","00","01", 9.32], ["2017","00","01", 6.88]]
let max = Math.max(Number(...arr.map((o) => { return o[3] }))); //9.99
let min = Math.min(Number(...arr.map((o) => { return o[3] }))); //9.99
console.log(min);
console.log(max);
let arr = [["2019","00","01", 9.99], ["2018","00","01", 9.32], ["2017","00","01", 6.88]];
let max = Math.max(...arr.map((o) => { return o[3] })); //9.99
let min = Math.min(...arr.map((o) => { return o[3] })); //6.88
console.log({
max , min
})
Earlier, you had put Number around the mapped array. This converts the array to a number. However, you only wanted the individual elements to be numbers so move it inside the map function.
let arr = [
["2019","00","01", 9.99],
["2018","00","01", 9.32],
["2017","00","01", 6.88]
];
let max = Math.max(...arr.map((o) => { return Number(o[3]) })); //9.99
let min = Math.min(...arr.map((o) => { return Number(o[3]) })); //6.88
// this can be rewritten like so:
// Math.min(...arr.map((o) => Number(o[3])));
//
// https://www.w3schools.com/js/js_arrow_function.asp
console.log(max);
console.log(min);
So,
before:
let min = Math.min(Number(...arr.map((o) => { return o[3] }))); //9.99
after
let min = Math.min(...arr.map((o) => { return Number(o[3]) })); //6.88

Usage of Promise.All in recursion doesn't seems to be working

Actual doSomething function posts ele to a remote API to do some calculations.
My calc function supposed to get the summation of the remote API's calculation for each element, It should run for every element without affecting how nested they are located.
However, Currently, I can't get this to work. How do I fix this?
const doSomething = (ele) => new Promise(resolve => {
console.log(ele);
resolve(ele * 2);//for example
})
const calc = (arr) => new Promise(
async(resolve) => {
console.log(arr.filter(ele => !Array.isArray(ele)));
let sum = 0;
const out = await Promise.all(arr.filter(ele => !Array.isArray(ele))
.map(ele => doSomething(ele)));
sum += out.reduce((a, b) => a + b, 0);
const out2 = await Promise.all(arr.filter(ele => Array.isArray(ele))
.map(ele => calc(ele)));
sum += out2.reduce((a, b) => a + b, 0);
resolve(sum);
}
)
const process = async () => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]];
const out = await calc(arr);
console.log(out);
}
process();
While it may look like I've addressed issues that are non-existent - the original code in the question had ALL the flaws I address in this answer, including Second and Third below
yes, the code in the question now works! But it clearly was flawed
First: no need for Promise constructor in calc function, since you use Promise.all which returns a promise, if you make calc async, just use await
Second: dosomething !== doSomething
Third: out2 is an array, so sum += out2 is going to mess you up
Fourth: .map(ele => doSomething(ele)) can be written .map(doSoemthing) - and the same for the calc(ele) map
So, working code becomes:
const doSomething = (ele) => new Promise(resolve => {
resolve(ele * 2); //for example
})
const calc = async(arr) => {
const out = await Promise.all(arr.filter(ele => !Array.isArray(ele)).map(doSomething));
let sum = out.reduce((a, b) => a + b, 0);
const out2 = await Promise.all(arr.filter(ele => Array.isArray(ele)).map(calc));
sum += out2.reduce((a, b) => a + b, 0);
return sum;
}
const process = async() => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10, 11]]];
const out = await calc(arr);
console.log(out);
}
process();
Can I suggest a slightly different breakdown of the problem?
We can write one function that recursively applies your function to all (nested) elements of your array, and another to recursively total the results.
Then we await the result of the first call and pass it to the second.
I think these functions are simpler, and they are also reusable.
const doSomething = async (ele) => new Promise(resolve => {
setTimeout(() => resolve(ele * 2), 1000);
})
const recursiveCall = async (proc, arr) =>
Promise .all (arr .map (ele =>
Array .isArray (ele) ? recursiveCall (proc, ele) : proc (ele)
))
const recursiveAdd = (ns) =>
ns .reduce ((total, n) => total + (Array .isArray (n) ? recursiveAdd (n) : n), 0)
const process = async() => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10, 11]]];
const processedArr = await recursiveCall (doSomething, arr);
const out = recursiveAdd (processedArr)
console.log(out);
}
process();
I think a generic deepReduce solves this problem well. Notice it's written in synchronous form -
const deepReduce = (f, init = null, xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r, x)
: f(r, x)
, init
)
Still, we can use deepReduce asynchronously by initialising with a promise and reducing with an async function -
deepReduce
( async (r, x) =>
await r + await doSomething(x)
, Promise.resolve(0)
, input
)
.then(console.log, console.error)
See the code in action here -
const deepReduce = (f, init = null, xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r, x)
: f(r, x)
, init
)
const doSomething = x =>
new Promise(r => setTimeout(r, 200, x * 2))
const input =
[1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]]
deepReduce
( async (r, x) =>
await r + await doSomething(x)
, Promise.resolve(0)
, input
)
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116
console.log("doing something. please wait...")
further generalisation
Above we are hand-encoding a summing function, (+), with the empty sum 0. In reality, this function could be more complex and maybe we want a more general pattern so we can construct our program piecewise. Below we take synchronous add and convert it to an asynchronous function using liftAsync2(add) -
const add = (x = 0, y = 0) =>
x + y // <-- synchronous
const main =
pipe
( deepMap(doSomething) // <-- first do something for every item
, deepReduce(liftAsync2(add), Promise.resolve(0)) // <-- then reduce
)
main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]])
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116
deepMap and deepReduce generics. These are in curried form so they can plug directly into pipe, but that is only a matter of style -
const deepReduce = (f = identity, init = null) => (xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r)(x)
: f(r, x)
, init
)
const deepMap = (f = identity) => (xs = []) =>
xs.map
( x =>
Array.isArray(x)
? deepMap(f)(x)
: f(x)
)
liftAsync2 takes a common binary (has two parameters) function and "lifts" it into the asynchronous context. pipe and identity are commonly available in most functional libs or easy to write yourself -
const identity = x =>
x
const pipe = (...fs) =>
x => fs.reduce((r, f) => f(r), x)
const liftAsync2 = f =>
async (x, y) => f (await x, await y)
Here's all of the code in a demo you can run yourself. Notice because deepMap synchronously applies doSomething to all nested elements, all promises are run in parallel. This is in direct contrast to the serial behaviour in the first program. This may or may not be desirable so it's important to understand the difference in how these run -
const identity = x =>
x
const pipe = (...fs) =>
x => fs.reduce((r, f) => f(r), x)
const liftAsync2 = f =>
async (x, y) => f (await x, await y)
const deepReduce = (f = identity, init = null) => (xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r)(x)
: f(r, x)
, init
)
const deepMap = (f = identity) => (xs = []) =>
xs.map
( x =>
Array.isArray(x)
? deepMap(f)(x)
: f(x)
)
const doSomething = x =>
new Promise(r => setTimeout(r, 200, x * 2))
const add =
(x, y) => x + y
const main =
pipe
( deepMap(doSomething)
, deepReduce(liftAsync2(add), Promise.resolve(0))
)
main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]])
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116
console.log("doing something. please wait...")

How can i mix all of the arithmetical operators to finish my calculator

I had a calculator Project.I can multiply,add,divide and substract all the numbers in the input and get the result like output.
But i need help.How is the solution when the user
in same input wants first to substract,then divide then multiply and and etc. in this case.
A little explanation: I have the buttons with atribbutes and i added event listener when they are clicked they need to be showed on the screen.
After that i pushed them in array and then depen on the arithetic operation,,/,+,- i make search with reg ex and after that i remove them and i make the operation ab, a + b etc depending on that what includes the array when the = EQUAL BTN IS PRESSED. Can include *,/,+,- but in this case just one of that arithmetic operator.
const btns = document.querySelectorAll(".btn");
const screen = document.querySelector(".screen");
const equalBtn = document.querySelector(".btn-equal")
const clearBtn = document.querySelector(".btn-clear")
let get = []
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
let number = btns[i].getAttribute("data-num");
screen.value += number;
get.push(number);
console.log(get);
})
}
equalBtn.addEventListener("click", function() {
if (get.includes("*")) {
const res = get.toString()
.match(/[^*]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Multiply = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a * b;
});
screen.value = Multiply;
}
if (get.includes("/")) {
const res = get.toString()
.match(/[^/]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Divide = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a / b;
});
screen.value = Divide;
}
if (get.includes("+")) {
const res = get.toString()
.match(/[^+]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Adding = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return parseInt(a) + parseInt(b);
});
screen.value = Adding;
}
if (get.includes("-")) {
const res = get.toString()
.match(/[^-]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Substracting = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a - b;
});
screen.value = Substracting;
}
});
clearBtn.addEventListener("click", function() {
get.length = 0;
screen.value = "";
});

const is undefined within reduce method

avgPrice(data) {
const min_price = data.min_price,
max_price = data.max_price;
console.log(min_price) //has value
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
}, { min_price:min_price, max_price:max_price });
}
What's wrong with my code above? I got min_price is undefined error. But my const min_price has value when I do console.log.
You have to return from reduce (return a so it can be used for the next iteration).
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
return a; //<<<<<
}, { min_price:min_price, max_price:max_price });
No mutation:
Although I don't see a reason why.
let x = _.reduce(data.custom_pricing, (a, b) =>
({ min_price: Math.min(a.min_price, b.min_price), max_price: Math.max(a.max_price, b.max_price) }), // create a new object and return it
{ min_price:min_price, max_price:max_price });

map(), reduce() and filter vs forEach()

I have just learned about MapReduce, so I wondered if there are any advantages in writing
const initialValue = 0;
if (this.items) {
return this.items.filter(function (item) {
return item && item.quantity && item.price;
}).reduce(function(previousValue, currentValue) {
return previousValue + currentValue.quantity * currentValue.price ;
}, initialValue);
} else {
return initialValue;
}
instead of just
let total = 0;
if (this.items) {
this.items.forEach(function(item) {
if (item && item.quantity && item.price) {
total += item.quantity * item.price;
}
});
}
return total;
For future readers, there are a few more idiomatic ways to write the reduction in a functional way.
These are generally used because they convey intent a bit more cleanly (and don't add a variable to the scope).
Note: I am assuming this.items has type
({ quantity: number; price: number } | undefined)[] | undefined
but each of the examples is tolerant to even more invalid data than the two in the question.
Filtering and mapping before reducing
Default value at the end
return this.items
?.filter(item => item?.quantity && item.price)
.map(item => item.quantity * item.price)
.reduce((a, b) => a + b, 0) ?? 0
Default array at the start
return (this.items ?? [])
.filter(item => item?.quantity && item.price)
.map(item => item.quantity * item.price)
.reduce((a, b) => a + b, 0)
Handling the filter within the map
I would not recommend these just because the previous two convey intention more clearly.
Default value at the end
return this.items
?.map(item => (item?.quantity ?? 0) * (item?.price ?? 0))
.reduce((a, b) => a + b, 0) ?? 0
Default array at the start
return (this.items ?? [])
.map(item => (item?.quantity ?? 0) * (item?.price ?? 0))
.reduce((a, b) => a + b, 0)
Destructuring
Each of the previous examples can be done with destructuring instead.
I am including one example.
return (this.items ?? [])
.filter(item => item) // Ensure item exists; sufficient for the cases we need to worry about
.map(({ price = 0, quantity = 0 }) => quantity * price)
.reduce((a, b) => a + b, 0)
Without a map
We can now do the reduction without a map.
This can also be done without destructuring, but that is seemingly (to me) inelegant.
return (this.items ?? [])
.filter(item => item)
.reduce((sum, { price = 0, quantity = 0 }) => sum + quantity * price, 0)
Of course, you can change the filter condition, which takes us back to roughly the first example in the question:
return (this.items ?? [])
.filter(item => item?.price && item.quantity)
.reduce((sum, { price, quantity }) => sum + quantity * price, 0)
Original forEach loop
Some of these changes can be made to the original loop, too:
let total = 0;
items?.forEach((item) => {
if (item?.quantity && item.price) {
total += item.quantity * item.price;
}
});
return total;
I can't see any advantage of the first over the second*. However the second is even faster then the first and looks more clean! The purpose of the first might be to demonstrate the use of built-in array-functions.
However mapreduce is used for a lot of Elements, so you might the speed it up as much as you can. This should be the fastest you can get:
const initialValue = 0;
let total = initialValue;
if (this.items) {
for (var i = this.items.length; i--;) {
let item = this.items[i]
if (item && item.quantity && item.price) {
total += item.quantity * item.price;
}
}
return total;
} else {
return initialValue
}
In addtion you could drop the if inside the loop, if you know that your array is consitant. Both ifs are just there to make sure the array is properly build and the script doesn't run into an Error, that would be usefull for userdata input, but in a closed system you don't need them.
*I noticed that, the second is missing the default value return initialValue

Categories