3

I want to determine how many of the items in these two arrays match, then store that in state as a number.

For example

const [score, setScore] = React.useState(0)

const selections = ["one", "two", "three"]
const allCorrectAnswers = ["four", "two", "three"]
// this should return 2

I tried

function checkSelectedAnswer(selections, allCorrectAnswers) {
  selections.map(eachChoice =>
    eachChoice === allCorrectAnswers.map(eachAnswer => eachAnswer) 
      ? setScore(prevScore => prevScore + 1) : 0
  )
}

Please explain why my code isn't working as well if you can.

agm
  • 91
  • 1
  • 6
  • Does this answer your question? [Check if array contains all elements of another array](https://stackoverflow.com/questions/53606337/check-if-array-contains-all-elements-of-another-array) – Heretic Monkey Feb 07 '22 at 19:51
  • One-liner if you don't mind `allCorrectAnswers.filter(ans => selections.includes(ans)).length` – A1exandr Belan Feb 07 '22 at 20:02
  • See also [How to check if two arrays are equal with JavaScript?](https://stackoverflow.com/q/3115982/215552) – Heretic Monkey Feb 07 '22 at 20:12

3 Answers3

2

.map (either at the top level or the nested one) doesn't make sense, because you aren't trying to transform each element of one array into another. If you want to use an array method, use .reduce instead, and use the index in the callback to access the associated element in the other array to see if it's equal.

const selections = ["one", "two", "three"];
const allCorrectAnswers = ["four", "two", "three"];
const totalCorrect = selections.reduce(
  (correctSoFar, answer, i) => correctSoFar + (answer === allCorrectAnswers[i]),
  0
);
console.log(totalCorrect);
// setScore(totalCorrect);

or do

const selections = ["one", "two", "three"];
const allCorrectAnswers = ["four", "two", "three"];

let totalCorrect = 0;
selections.forEach((answer, i) => {
  if (answer === allCorrectAnswers[i]) {
    totalCorrect++;
  }
});
console.log(totalCorrect);
// setScore(totalCorrect);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • the thing is I'm using state to measure this as it's a react app and I need to render the result eventually when a button is clicked. I believe this is what I need to do vs your suggestion. I tried this with your code but it's not working: function checkSelectedAnswer() { selections.forEach((answer, index) => { if (answer === allCorrectAnswers[index]) { setScore(score + 1); } }); } – agm Feb 08 '22 at 00:09
  • Use *my* code, rather than altering it - your altered version won't work because you're setting the state inside the loop. Calculate the total number of correct answers, *then* set the state with the final calculation. – CertainPerformance Feb 08 '22 at 00:59
  • I'm actually still on this can you check this to see why my score isn't working consistently? I used your code but only stored the result in state because I wasn't able to access totalCorrect outside of my function otherwise https://scrimba.com/scrim/co6a240dfa1cc064e4dffd2f6 thanks – agm Feb 10 '22 at 18:33
  • Not sure what the issue is, your code looks to be working fine for me: https://i.stack.imgur.com/apZgS.png Setting the state is perfectly normal - with that approach you can then reliably access the value from anywhere. – CertainPerformance Feb 10 '22 at 18:57
  • The issue was when answering in the wrong order (ie 2nd question, then 4th, then 1st..) the correct result doesn't add up – agm Feb 11 '22 at 19:15
  • Your `handleSelectedAnswer` isn't taking into account the answer index. Put the made answers into an object indexed by question index instead of an array. `updateAnswers={(e) => setUserAnswers({...userAnswers, [index]: e.target.value })}` and then compare the values in the object - where `userAnswers` is initialized to an empty object – CertainPerformance Feb 11 '22 at 19:43
  • Assuming you're saying to create a new state: userAnswers, setUserAnswers, then pass in that code into updateAnswers which will go into the other component as a prop? If so, it's giving me an error on click of an input – agm Feb 12 '22 at 03:10
  • What error? Hard to figure things out without a precise description of the problem – CertainPerformance Feb 12 '22 at 03:23
  • Sorry I'm going to take today off and get back to you tomorrow. Thank you – agm Feb 12 '22 at 03:46
  • I couldn't find the error anymore today, but it's not adding up. On button click it should be displaying the number of correct answers: https://replit.com/join/kejlamxjqw-arshia93 – agm Feb 12 '22 at 17:40
  • Your link is giving me a login and signup page, rather than your code. Please edit the relevant code into your question. – CertainPerformance Feb 12 '22 at 17:50
  • It says my code is too long here can you try this: https://replit.com/@arshia93/Quizzical#sections/QuizData.jsx – agm Feb 12 '22 at 17:57
  • You are still setting the state inside the loop, which as I said before you shouldn't do. Set the state only outside the loop. (Consider using a linter or a decent IDE so that your indentation is proper - this will make it clearer where blocks, like loops, begin and end) – CertainPerformance Feb 12 '22 at 18:21
  • Yeah that was my idea of moving from scrimba editor to replit. I moved setScore but not working can you check again? – agm Feb 12 '22 at 18:25
  • Now you aren't calling `updateAnswers` in `Question.jsx`. Per Stack Overflow guidelines, for questions to be on-topic here, all relevant code should be in the question itself - please make an effort to do so – CertainPerformance Feb 12 '22 at 18:29
  • I'm sorry I didn't realize that it wasn't there, must not have updated my code over from Scrimba. I only recently made a stackoverflow so I thought id just post the part that had an issue. Is it frowned upon to share a IDE url in a question? I added onChange={updateAnswers} to Question. Do you see any other issues preventing me from getting the right score? – agm Feb 12 '22 at 18:33
  • This is looking to be turning into a [chameleon question](https://meta.stackexchange.com/questions/43478/exit-strategies-for-chameleon-questions) - see that link, there are many things you're asking about that you weren't asking about originally (nor is a MCVE for any of those additional issues in the question). If you have a separate question, it should be in a separate post, with all the information needed to answer it in a MCVE. – CertainPerformance Feb 12 '22 at 18:36
  • That's understandable. I'll work on this and if I still can't get a answer I'll make a more appropriate post. If I do, is it ok to share the similar replit url in the question rather than copy/pasting 100 lines of code between 2 components? Thanks – agm Feb 12 '22 at 19:56
0

First of all, I would suggest to use a Set to avoid duplicate values and then an intersection to see what element matches.

const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
const intersection = new Set([...a].filter(x => b.has(x)));
    // {2,3}

Using Set, you will also improve performance since there is no duplicate values.

Here is a small benchmark

Checked test: Javascript Set intersection x 70,358 ops/sec ±2.26% (61 runs sampled)
Checked test: Javascript Array intersection x 40,687 ops/sec ±1.22% (67 runs sampled)
Success! Validation completed.

Your code does not work since you comparing the answer (a string) with an array of item which end up to be always false.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Adrien De Peretti
  • 3,342
  • 16
  • 22
-1

You can use filter method and its second parameter that is index. After you filter for all elements that match in two arrays, you can just return the length property witch will present the number of matches.

const selections = ["one", "two", "three"];
const allCorrectAnswers = ["four", "two", "three"];

const checkSelectedAnswer = (selections, allCorrectAnswers) => selections.filter((eachChoice,index) => eachChoice === allCorrectAnswers[index]).length;

const numberOfCorrectAnswers = checkSelectedAnswer(selections, allCorrectAnswers);
console.log(numberOfCorrectAnswers);
ggorlen
  • 44,755
  • 7
  • 76
  • 106
NeNaD
  • 18,172
  • 8
  • 47
  • 89
  • I'd prefer `forEach` or `reduce`. This method allocates a potentially huge array O(n) memory just to toss it out again after checking its length. – ggorlen Feb 07 '22 at 19:51