A problem with array and checking the values inside - javascript

Hello recently I was working with arrays in JavaScript and appear a little problem with a function.
My problem is in the function checkRepeat, in this function I try to know if I click a Card before or not, when I click the first Card work but with the other cards they don't work, I was thinking that my problem maybe it's for the loop because maybe it's taking only one element but I don't know.
This is my code:
const cardArray = [
{name: 'fries'},
{name: 'pizza'},
{name: 'hotdog'},
{name: 'cheeseburger'},
{name: 'milkshake'},
{name: 'ice-cream'}
]
const emptyCard = [
{name: 'white'},
{name: 'blank'}
]
// the format of the img
const format = '.png'
// I select the place where I gonna put the board
const grid = document.querySelector('.grid');
const cardsChosen = [];
const cardsChosenId = [];
const createBoard = () =>{
for(let n = 0; n < cardArray.length*2; n++)
{
// I create the img
let card = document.createElement('img');
card.src = `images/${emptyCard[1].name}${format}`;
card.id = `card-${n}`
card.addEventListener('click',flipCard)
grid.appendChild(card)
}
}
function flipCard(){
// I get the id, just the number
let cardId = parseInt(this.getAttribute('id').slice(5,7));
const v1 = checkRepeat(cardsChosenId,cardId);
console.log("Value: ",v1)
//console.log("Values in the array: ",cardsChosenId)
}
function checkRepeat(array,value){
if(array.length === 0){// if the array is empty
array.push(value);//push in the array the value
return true;// and return true
}
else{// if isn't
for(let i = 0; i < array.length; i++){// walk through the array
if(array[i] === value){// check if the values of the array === value
return false;
}
else{// if the value and the array values are different
array.push(value);//push the value
return true;
}
}
}
}
createBoard();

I found the error in the code, the problem was the logic.
Because when it traversed the array, it finds an equal value, but it continues traversing the array and the other values ​​do not resemble the compared value, so it adds the same values ​​to me later in the array.
I explain:
When I click on each of the cards, they save the id in an arrangement, and if I click again on a card that I had previously given it, it would compare with each element and when it found the same one, it would return false, but continued scrolling the whole arrangement and added more elements to the arrangement when I shouldn't have.
Example:
I click on the 1st element, [0] is saved, I click on the second [0,1] and I give the second element again and when comparing 0 with 1 I find that they are different and it remains like this [0,1,1] when it should return only [0,1]
I resolve with includes:
function checkRepeat(array,value){
if(array.includes(value)){//return true if value it's in the array
return false;
}
else{
array.push(value);
return true;
}
}

Related

How to compare the values in a list and the value that is compared to will be inserted to the front or back if its larger or smaller?

I am creating a function that inserts an element into a list only if the element to be inserted
is larger than any of the elements currently in the list. Larger can mean either greater
than when working with numeric values, or further down in the alphabet, when
working with textual values.
var names = new List();
function List(){
this.dataStore = [];
this.listSize = 0;
this.pos = 0;
this.append = append;
}
function append(element){
for (i = 0; i > this.dataStore.value;++i){
if (names.value == this.dataStore[i].value){
this.dataStore[this.listSize++] = element;
this.pos++;
}
}
}
function insert(element, after) {
var insertPos = this.find(after);
if (insertPos > -1) {
this.dataStore.splice(insertPos+1, 0, element);
++this.listSize;
return true;
}
return false;
}
function find(element){
for (var i = 0; i < this.dataStore.length;++i){
if(this.dataStore[i]== element){
return i;
}
}
return -1;
}
names.append("Jascien");
console.log(names);
names.append("Jas");// i want to insert this value after its compared to the exiting values in the front of the first value or after it.
console.log(names);
names.append("John"); // also this one
console.log(names);
By numeric values you mean number as string, or number as Number. If number as Number, then I think it would be good to divide this condition check in two separate condition check, depending on type of data entered as element.
As written above, please provide some input and output arrays for better understanding what you expect from this function.

Incrementing values in loop acting weird - JavaScript

I have a code that checks indexes of array with some ID's, and increases some order value for items with those ID's. The code looks something like this:
function changeOrder(initialIndex, newIndex, itemsMap, itemIds) {
const requestPayload = [];
itemsMap[itemIds[initialIndex]].order = itemsMap[itemIds[newIndex]].order;
requestPayload.push(itemsMap[itemIds[initialIndex]]);
if (initialIndex > newIndex) {
for (let i = newIndex; i < initialIndex; i++) {
itemsMap[itemIds[i]].order++;
requestPayload.push(itemsMap[itemIds[i]]);
}
}
console.log(requestPayload);
return requestPayload;
}
Now, the issue is when i hover over the requestPayload inside the console.log, order values are correct (0, 1, 2 in my case). But once it does the logging, or returns the requestPayload, values are 1, 2, 3. Function is triggered only once, so it doesn't increment them again. Here is the screenshot, you can see when I manually log the values when breakpoint is set vs logged payload.
EDIT: Solved with the help from #Pointy in the comments:
for (let i = newIndex; i < initialIndex; i++) {
const copy = { ...itemsMap[itemIds[i]] };
copy.order++;
requestPayload.push(copy);
}

Trying to make a function to find if an array has more of one value than another

I am working on a simple project where the users are asked questions, and I am recording their answers in an array (value of 0 for yes, and a value of 1 for no). I'm just a beginner so please explain the code you send me.
I haven't tried anything but I think the best way to do it is to make a function where if the values of the array are greater than 0 it should display a certain result for the test, and if its equal to zero it should display a different result (I have no clue how to achieve this).
questionOneInputYes.addEventListener("click", function() {
if (questionTwo.style.display="none") {
questionTwo.style.display="block";
answerData.push(0);
}
})
questionOneInputNo.addEventListener("click", function() {
if (questionTwo.style.display="none") {
questionTwo.style.display="block";
answerData.push(1);
}
})
Instead of using an array, I would suggest using a dictionary with two keys: one for yes, one for no. So instead of creating an array of ones and zeroes, create a dictionary. For example:
let answers = {
'yes': 0,
'no': 0
}
Then you can increment either yes or no based on the button clicked:
questionOneInputYes.addEventListener("click", function() {
if (questionTwo.style.display="none") {
questionTwo.style.display="block";
answers['yes'] +=1;
}
})
This has the benefit of being a much more meaningful data structure (not just an array of 1's and 0's), and you already have access to the totals without any additional calculation needed, so it is trivial to check if there are more yes or no answers:
answers['yes'] > answers['no']
If you have a large number of questions, hardcoding it like above may be a pain. You could create an array of questions and loop them to generate the html. Please read the code and ask in case of doubts.
var container = document.querySelector(".questionContainer");
var questions = ["Hello?","World?","Foo?","Bar?"]; // add more questions to the array as required
var answerData = [];
/* Read on Array.prototype.reduce and Arrow Operators on MDN.
Basically it runs a for loop in the array and updates a temporary variable with some value */
var questionHTML = questions.reduce((_html,question,index) => {
/*
For each question, it creates and appends the above HTML code to the
container. For first question, set display to block and set display
none for all other question. This will be modified when someone
submits an answer. We are using the same submitAnswer function in
both buttons and changing the value based on YES/NO. ${} is used to
put the value from a variable in template strings.
*/
_html += `<div id="q-${index}" style=" display:${index===0? 'block' : 'none'}"><p> ${question} <\p>
<button onclick="submitAnswer(0,${index})"}>NO</button>
<button onclick="submitAnswer(1,${index})">YES</button>
</div>
`
return _html;
} ,"");
function submitAnswer(value, index) {
// add the value of YES/NO according to button into the answer array at the specified index
answerData[index] = value;
// console.log(answerData);
if(index < questions.length - 1){ // for all questions except the last question, -1 since the numbers are from 0...length-1 for an array , we select the currentQuestion and nextQuestion with the id we had assigned to the div during the html creation using reduce as above. Then we set current question to display none and next question to display block.
currQuestion = document.querySelector(`#q-${index}`);
nextQuestion = document.querySelector(`#q-${index+1}`);
currQuestion.style.display = "none";
nextQuestion.style.display = "block";
} else {
// after all questions are completed, show finished.
container.innerHTML = "<p>You have finished the quiz</p> answers : "+ answerData.join(',')
// do something with the answerData array
}
}
container.innerHTML = questionHTML;
<div class="questionContainer">
</div>
Let's say you have, at the end of the quiz an answerData that looks like:
[1, 1, 0, 0, 1, 0, 1, 1]
you can now use Array.prototype.reduce()
const answerData = [1, 1, 0, 0, 1, 0, 1, 1];
const noTot = answerData.reduce((acc, curr)=> acc + curr) ;
console.log( noTot ) // 5
And you'll get 5 as the result for NO answered questions
Stop repeating yourself! Programming is not meant to copy-paste code (like in your example, every question has it's own dedicated slightly-renamed copy-pasted listener and handler function...).
Instead, create a counter to keep track of the progress, you need only two buttons, and a single DIV for your questions:
const elQ = document.querySelector("#question"); // Cache elements
const elBtn = document.querySelectorAll(".answer");
const QA = [ // Array of Objects ("a:" answers will be populated during the quiz)
{q:"Do you like coding?"},
{q:"Are you tall?"},
{q:"Are you hungry?"},
{q:"Are you thirsty?"},
];
let c = 0; // Start counter at index 0 (first QA question)
const askQuestion = () => elQ.textContent = QA[c].q; // Show question
const setAnswer = (btn) => QA[c].a = parseInt(btn.value, 10); // Populate with answer
const showResult = () => {
console.log(QA);
Array.from(elBtn).forEach(el => el.disabled = true); // Disable buttons
const nopes = QA.reduce((acc, curr) => acc + curr.a, 0); // Total of NO answers
elQ.innerHTML = `
Tot questions: ${QA.length}<br>
Yes answers: ${QA.length - nopes}<br>
No answers: ${nopes}
`;
};
const handleAnswer = (ev) => {
setAnswer(ev.target);
if(c === QA.length-1 ) return showResult();
c++;
askQuestion();
};
// Events
Array.from(elBtn).forEach(el => el.addEventListener('click', handleAnswer));
// Start!
askQuestion();
<div id="question"></div>
<button class="answer" type="button" value="0">YES</button>
<button class="answer" type="button" value="1">NO</button>
If all you're trying to do is see if there are more zero's than ones in your array and vise versa, you can filter out all the 1s in your array into another array and get the length of the array containing the ones. Here I have used .filter(Boolean) which will give you an array of ones. This works because a 1 in javascript is "truthy". (This is somewhat equivalent to doing .filter(n => n===1))
Next, you can get the number of zeros in the array by subtracting the numbers of ones from the length of the array
You can then compare the number of ones and zeros using an if statement and output the associated message
See example below:
const arr = [1, 1, 1, 0, 0],
ones = arr.filter(Boolean).length, // gives length of [1, 1, 1] (3)
zeros = arr.length - ones; // gives remaining 2 ([0, 0])
console.log(ones, zeros);
if(ones > zeros) {
console.log("There are more ones in the array than zeros")
} else if(ones < zeros){
console.log("There are more zeros in the array than ones");
} else {
console.log("The same amount is in both");
}

Search for the key in the given array of objects and replace the value;

Implementing the multiple sort functionality; Where need to toggle the array which hold the sorting fieldname and sorting order;
Example
Click Sort By Name:
[{"sortKey":"name","sortValue":"desc"}]
Again Click Sort By Name:
[{"sortKey":"name","sortValue":"asc"}]
Click Sort By Age:
[{"sortKey":"name","sortValue":"asc"},{"sortKey":"age","sortValue":"desc"} ]
Again Click Sort By Name:
[{"sortKey":"name","sortValue":"desc"},{"sortKey":"age","sortValue":"desc"} ]
DEMO
if (checkIfObjectExists($scope.sortList, sortingObject)) {
if (!$scope.sortList.hasOwnProperty(sortingObject.sortType)) {
console.log($scope.sortList);
// replace the value for the key
}
} else {
$scope.sortList.push(sortingObject);
}
I changed some things in your implementation. Problem was you were checking if the whole object is not same then push in the array. But what you need if sorKey is same reverse the sortValue.
DEMO
Changed your function checkIfObjectExists to updateArray.
function updateArray(array, newObject) {
var i = 0;
for (i = 0; i < array.length; i++) {
var object = array[i];
if (object.sortKey == newObject.sortKey) {
object.sortValue= (object.sortValue==='asc')?'desc':'asc';
return;
}
}
array.push(newObject);
}
And while calling I will just call like this in $scope.clickMe.
updateArray($scope.sortList, sortingObject);

JSON.stringify() causing an infinite loop (Edit: NO. Bad logic is.)

My product object looks somewhat like this:
{name: 'abc', description: 'def', price: 100, quantity: 1, comment: '', customizations: []}
The customizations key is an array that has other such product objects in it. You may ignore it for this question. As you might have noticed, the comment and customizations keys are the keys that make the (theoretically) same product (practically) different when adding to cart.
I want to make a function to add such products to an array called cart_items[]. If the (practically) same product is chosen, I only want to increment the quantity inside the cart_items[i], else add a new object.
This is my function:
$scope.add_to_cart = function(product) {
// if the cart is empty, skip the brouhaha
if ($scope.cart_items.length === 0) {
$scope.cart_items.push(angular.copy(product));
} else {
for (var i = 0; i < $scope.cart_items.length; i++) {
// copy the original quantity and set it to 1 for comparison
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
} else {
$scope.cart_items[i].quantity = qty;
$scope.cart_items.push(angular.copy(product));
}
}
}
};
The problem: First product adds successfully. Adding another causes an infinite loop. I replaced if(JSON...) with if(1 === 1) and the infinite loop didn't occur. I don't know where am I going wrong. Any help?
The problem you have is that you're increasing the size of the array in the loop and the stop condition is i being $scope.cart_items.length.
If your goal is to add the object if it's not yet present, what you want is probably this :
boolean found = false;
for (var i = 0; i < $scope.cart_items.length; i++) {
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
found = true;
break;
}
}
if (!found) {
var item = angular.copy(product);
item.quantity = 1;
$scope.cart_items.push();
}
Note that two identical objects (i.e. objects with same property values) should not give the same JSON string because the order of property iteration isn't specified. It usually works (especially if the cloning is done the obvious way) but there's no guarantee. You really should compare based on the properties, not using JSON stringification.
You probably enter in a recursive loop, because of objects contained in customizations...
A [ customizations = B ]
B [ customizations = C ]
C [ customizations = A ]
----------------------------
Infinite loop

Categories

Resources