For Loop items aren't adding into basket - javascript

My sumUpItems function works well. However, I am having problems with adding up items into basket. The second function isn't working. What I am doing wrong?
sumUpItems() {
let sum = 0;
for (const item of this.basketItems) {
sum += Number.parseFloat(item.price);
}
return sum;
},
basketCount() {
let count = 0;
for (let item of this.basketItems) {
count = ++item;
}
return count;
}
}

sumUpItems()
You can simplify the sumUpItems by using the reduce function which you can call on an array this.basketItems.
The most short way is:
sumUpItems() {
return this.basketItems.reduce((totalPrice, basketItem) => totalPrice + basketItem.price, 0);
}
What the reduce function does is it executes a reducer function on each element of the array, resulting in single output value, in this case the totalPrice of all basketItems.
if you are more comfortable with brackets you could write it down like this:
sumUpItems() {
return this.basketItems.reduce((totalPrice, basketItem) => {
return totalPrice + basketItem.price;
}, 0);
}
Or in ES5 javascript (without arrow function):
sumUpItems() {
return this.basketItems.reduce(function(totalPrice, basketItem) {
return totalPrice + basketItem.price;
}, 0);
}
I recommend you to rename the sumUpItems() function name to getTotalPrice() or something like that, it describes more specifically what the function does and returns.
BasketCount()
The reason why basketCount() is not returning the correct amount of items is because the incrementation of the variable count is invalid. let item holds the object value of the array item inside this.basketItems and you are trying to add this object to a number.
What you can do is return the length of the this.basketItems directly by writing:
basketCount() {
return this.basketItems.length;
}
Extra information
Reduce function documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
There are some powerfull methods that you can call on an array.
Most commonly the map, filter and reduce method. The reduce method is a bit tricky when you start using them but they can be handy in cases like this.
I recommend you to read this article on medium: https://medium.com/poka-techblog/simplify-your-javascript-use-map-reduce-and-filter-bd02c593cc2d or search on google for map,filter and reduce javascript arrays, it will help you a lot ;)

Check the code very well, in basketCount() function the count variable is not incrementing and besides you increment item by 1 before assigning its value into count;
Are you planning doing something like this;
count += ++item;
or
count += item;
It will be better if you can include code for basketItems also;

If you rewrote this section like so: it will work
basketCount() {
let count = 0;
for (let item of this.basketItems) {
++count;
}
return count;
}
But a better way of doing this will do like so:
let d = 0;
let p = arr.map(eachone => d++); //p contains your count
Another option using forEach:
let arr = [1,2,3,4,5]; //replace arr with this.baskets
let b = 0;
arr.forEach((eachone) => {
b++
});
LASTLY: if you dont want to create an unused variable:
let baskets = [1,2,3,4,5];
let p = 0;
for(i=0; i<=baskets.length; i++) {
p++;
}
return p;
Welcome to stackover flow :)

Related

Creating a Counter - Javascript

My apologies in advance if this is a very basic question/answer - I have searched, and am "old" learning for the first time and have found myself a little lost.
It's my first time coding, and basically I have an array (lets say fruits), I've been able to create it displaying the array and shuffling that array on click - which is exactly what I wanted (yay go me).
Now I am trying to have the ability to keep track of how many times I have clicked the shuffle button = before I either click reset, leave the page or refresh the page in which the counter resets.
This is where my trouble lays. I am having trouble 'inter-twining' the array + how many times I have clicked shuffle into my code. Honestly, I am getting confused, with so many 'help blogs' who all have different ways of doing things and I'd truly TRULY appreciate any help to get me sorted.
This is my current code to produce the list of fruits and being able to display it on my page.
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const r = Math.floor(Math.random() * (i + 1));
[arr[i], arr[r]] = [arr[r], arr[i]];
}
return arr;
};
const array = ["Apple", "Pear", "Apricot", "Nashy", "Kiwi", "Watermelon"];
function printArray(arr) {
return arr.reduce((acc, n, i) => {
return acc.concat(i < arr.length - 1 ? `${n}\n ` : `${n}`);
}, '');
};
function shuffle() {
const copiedArr = array.map(n => n);
const shuffledArray = shuffleArray(copiedArr);
document.getElementById("array").innerText = printArray(shuffledArray);
}
function restore() {
document.getElementById("array").innerText = printArray(array);
}
restore();
<div class="container">
<span id="array"><pre></pre></span>
</div>
<br>
<br>
<button onclick="shuffle()" value="randomize">Shuffle!</button>
<button onclick="restore()">Retore</button>
To be honest I have tried so many different things I am lost and confused. And so am hoping to start from scratch this is my code and I am trying to get a counter to keep track of every time I click shuffle that resets when Reset is clicked.
Here you go. While swahili geeks answer is correct. It is quite confusing for a learner.
So I took a different approach. You define a state object for your application and work upon it.
It would be nice to wrap the whole thing in a function to isolate the scope of declared functions and variables and not pollute the window, but you get there on your speed.
Also note how I am using a spread operator [...arr] to clone an array. No need to .map(n => n)
const state = {
originalArray: ["Apple", "Pear", "Apricot", "Nashy", "Kiwi", "Watermelon"],
currentArray: ["Apple", "Pear", "Apricot", "Nashy", "Kiwi", "Watermelon"],
numberOfShuffles: 0,
};
const outputElement = document.getElementById("js-array");
const counterElement = document.getElementById("js-count");
function formatArray(arr) {
return arr.reduce((acc, n, i) => {
return acc.concat(i < arr.length - 1 ? `${n}\n` : `${n}`);
}, "");
}
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const r = Math.floor(Math.random() * (i + 1));
[arr[i], arr[r]] = [arr[r], arr[i]];
}
return arr;
}
function shuffle() {
const copiedArr = [...state.currentArray];
const shuffledArr = shuffleArray(copiedArr);
state.currentArray = shuffledArr;
state.numberOfShuffles++;
updateUi();
}
function restore() {
state.currentArray = [...state.originalArray];
state.numberOfShuffles = 0;
updateUi();
}
function updateUi() {
outputElement.innerText = formatArray(state.currentArray);
counterElement.innerText = state.numberOfShuffles;
}
updateUi();
<pre id="js-array"></pre>
<br />
<span id="js-count"></span>
<br />
<br />
<button onclick="shuffle()">Shuffle!</button>
<button onclick="restore()">Restore</button>
The closure in JavaScript can be solution but it's a bit challenging to understand.
const add = (function () {
let counter = 0;
return function () {counter += 1;
return counter}
})();
// Call add() 3 times
add();
add();
add();
// the counter is now 3
The variable add is assigned to the return value of a self-invoking function.
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way add becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
This is called a JavaScript closure. It makes it possible for a function to have "private" variables.
The counter is protected by the scope of the anonymous function, and can only be changed using the add function.

Finding the sum of a variable amount of numbers in a given string

I am doing an exercise on JS Hero website:
Write a function add that takes a string with a summation task and returns its result as a number. A finite number of natural numbers should be added. The summation task is a string of the form '1+19+...+281'.
Example: add('7+12+100') should return 119.
The code I have written is as follows:
function add (string) {
let partsArray = string.split("+");
let added = parseInt(partsArray[0]);
for (let i=0; i<=partsArray.length; i++) {
added = added + parseInt(partsArray[i]);
}
return added;
}
It returns NaN. Any ideas how to solve this one?
You were going out of bounds on your array. Also you should just initialize the added to 0 as you start looking at the array from index 0. Note I added some console.logs to give you an idea of how you might debug something like this.
function add (string) {
let partsArray = string.split("+");
console.log("parts", partsArray);
let added = 0;
for (let i=0; i<partsArray.length; i++) {
console.log("i",parseInt(partsArray[i]));
added += parseInt(partsArray[i]);
}
return added;
}
If you add the <= back and run the code with the console.logs you will see in console the following. Note with the <= you have 4 indexes rather than the expected 3. This is because the size is 3 but the array is indexed from zero. When you use < you get the expected answer.
You could also use the reduce method:
function add(string) {
return string.split('+').reduce((accumulator, currentValue) => accumulator +
parseInt(currentValue, 10),0)
}
If you still want to start with the first index ..you can do it like below
function add (string) {
let partsArray = string.split("+");
let added = parseInt(partsArray[0]);
for (let i=1; i<partsArray.length; i++) {
added += parseInt(partsArray[i]);
}
return added;
}
function add(input) {
let myinput = input.split("+") //split your value
let sum = 0;
for (let i = 0; i < myinput.length; i++) {
sum = sum + +myinput[i]; //use + for identify the number value
}
return sum;
}
The simplest possible answer is:
function add(str){
return eval(str)
}

Trying to use forEach to add up values in my array - would I be better be using a for loop?

Apologies for the beginner question.
I'm used to use for loop and thought I would give a forEach function a try.
What I don't understand is that within the function, I need to declare my finalCount to zero but obviously it will get reset/cleared.
If I declare it before the function, obviously, it won't be accessible.
So I guess my question is that would a forEach be best or I should just stick to what I know best - the for loop
Code below.
items.forEach(function(item) {
var count = 0
var itemAmount = parseInt(item.itemRRPAmount);
console.log(itemAmount)
console.log("Item amount is: " + itemAmount)
var count = itemAmount + count
console.log("Final count = " + count)
})
Since you're iterating over all array items to combine into a single output value, it might be even more preferable to use reduce, which does not require any reassignment of variables, and is quite efficiently terse, which is pretty useful:
const totalCount = items.reduce((a, { itemRRPAmount }) => a + itemRRPAmount, 0);
Or, with forEach, the above would look like:
let totalCount = 0;
items.forEach(({ itemRRPAmount }) => {
totalCount += itemRRPAmount;
});
Or, if you don't like destructuring:
let totalCount = 0;
items.forEach((item) => {
totalCount += item.itemRRPAmount;
});

How to return an array of numbers from a function in asm.js?

I'm sure I could eventually figure this out, but the documentation is a bit verbose and I think this ought to be a common question about asm.js.
Here goes:
Suppose that I have a function that looks like this:
function computeSquares() {
var i, array = [];
for(i = 0; i < 100; i++) {
array.push(i * i);
}
return array;
}
The above function computes the square of the integers from 0 to 99 and returns an array containing the results.
I would like to write a function like this in asm.js that returns an object containing the 100 square values. If I've read the documentation, I'm supposed to use the ArrayBuffer object, but I'm a bit confused about how to do it.
Please illuminate me by giving an example of how to code this with asm.js.
You can only return doubles, signed ints and voids from exported functions. If you want to return an array you'll have to write it into the heap.
The module would look like this:
function squaresModule(stdlib, foreign, heap) {
"use asm";
var imul = stdlib.Math.imul;
var array = new stdlib.Uint32Array(heap);
function compute( max ){
max = max|0; //max is an integer
var i = 0;
for( i = 0; (i|0) < (max|0); i = (i+1)|0 ) {
array[ i <<2>>2 ] = imul(i, i)|0;
}
return 0; //asm functions have to return a number
}
return {compute:compute};
}
.
Then use execute and log the array:
var array = Uint32Array( 100 );
var module = squareModule(
{Math:Math,Uint32Array:Uint32Array}, {}, array.buffer
);
module.compute(100);
console.log(array);
Instead of returning an array, I write the results in a convenient representation inside asm.js and then extract it with a wrapper function in JS that repeatedly calls into asm.js code to get the next value:
var result = [];
var i = 0;
while (true) {
i = return_next_array_value_from_asmjs();
if (i !== 0) {
result.push(i);
} else {
break;
}
}
The downside is that you need to reserve at least one value as a stop marker. I have not tested the performance because I couldn't get any other method to work.

JavaScript array sort(function) to sort table rows- not sorting

I am trying to sort a dynamically constructed table on the client side. So far I have done my research to discover JavaScript's sort() method will take a callback. Here is what I have so far:
function retrvCatalog(e){
var merch = document.getElementById('merch');
var tRows = merch.rows;
var tBody = merch.tBodies;
var rowArr = [];
for (x in tRows){
rowArr[x] = tRows[x];
}
rowArr.sort(function(a, b){
if (a.cells.textContent < b.cells.textContent){
return -1;
}
if(a.cells.textContent > b.cells.textContent){
return 1;
}
return 0;
});
}
Stepping through it in Firebug, it appears to not change the order of the rows. Can someone please help me figure out what I am missing?
FINAL ALGORITHM
function retrvCatalog(e){
var fltr = e.id;
var merch = document.getElementById('merch');
var tblHead = merch.tHead;
merch.deleteTHead();
var tRows = merch.rows;
var rowArr = [];
for (var i=0; i<tRows.length; i++){
rowArr[i] = tRows[i];
}
rowArr = rowArr.sort(function(a, b){
if (fltr > 3){
a = parseFloat(a.cells[fltr].innerHTML);
b = parseFloat(b.cells[fltr].innerHTML);
}
else{
a = a.cells[fltr].innerHTML;
b = b.cells[fltr].innerHTML;
}
if (a>b){
return 1;
}
if(a<b){
return -1;
}
return 0;
});
while(merch.hasChildNodes()) {
merch.removeChild(merch.firstChild);
}
merch.appendChild(tblHead);
for (i=0;i<rowArr.length;i++){
merch.appendChild(rowArr[i]);
}
}
The final two columns in the row are numbers, so that is why the method to sort is slightly variable.
Several problems in your code.
First, you didn't declare the x variable.
for(var x...
Second, don't use for-in to iterate an array like collection. Use for.
for (var x = 0, len = tRows.length; x < len; x++){
rowArr[x] = tRows[x];
}
Third, there is no textContent property of a cells collection.
This is easy to test by logging its value. This should have been the first thing you tried.
console.log(a.cells.textContent); // undefined
You need to decide which cell you want, and ask for it by index.
console.log(a.cells[0].textContent);
Finally, you should be aware that this technique will not show the result of the sorting in the DOM. You're only sorting the Array. You'll need to append the new ordering to the DOM.
Maybe you knew this, but you didn't show it in your code.
I don't know the relationship of the rows to the tBodies, so I can't give an example. But if all the rows are in one tbody, just loop the Array, and tBody[0].appendChild(rowArr[i])
I'm not sure if I'm missing something, but I'm pretty sure you can't use textContent on the cells array. You need to index cells so you know which column to actually sort on. If your rows have 4 columns each (or even if there's only 1), you still need to tell the sort function which column to sort on.
So in your sort function, if you wanted to sort by the second column, you'd want something like:
rowArr.sort(function (a, b) {
if (a.cells[1].textContent < b.cells[1].textContent) {
return -1;
} else if (a.cells[1].textContent > b.cells[1].textContent) {
return 1;
}
return 0;
});
And I'm not sure what's in your cells, but you may want to use .innerHTML, not .textContent.
rowArr.sort(function(a,b) {
a = parseFloat(a.cells.textContent);
b = parseFloat(b.cells.textContent);
return (a-b);
};
"don't use for-in to iterate an array like collection." - user1673729
tRows is not an array, it's an HTML collection. That is why I used "for in" – nodirtyrockstar
An HTML Collection is an array like collection. Do not use for-in.

Categories

Resources