0

I have an array of objects that is basically like this.

const characters = [
{
id: 1
name: batman
biography: {
born-in: gotham
good-or-bad: good
}
stats: {
strength: 85
speed: 90
intelligence: 95
}
}
{
id: 2
name: superman
biography: {
born-in: krypton
good-or-bad: good
}
stats: {
strength: 90
speed: 85
intelligence: 80
}
}
{
id: 3
name: joker
biography: {
born-in: gotham
good-or-bad: bad
}
stats: {
strength: 70
speed: 95
intelligence: 100
}
}
]

Then, after mapping and displaying the objects in my page, I add a button that allows the user to mark the character as a favorite. The user can only add up to 6 favorites.

const [favorites, setFavorites = useState([]);

const addFavorite = () => {
favorites.length === 6 ?
console.log("favorites' list is full!") :
setFavorites(favorites.concat(character))
}

{characters.map((character)=>{
const {props} = character;
return (
<div>{props}</div>
<button onClick={addFavorite}>add to favorites</button>
);
})}

Now, what I want to do (and I don't know how to, after many attempts)

  1. preventing the user to add the same character twice to favorites. (I have tried with favorites.contains(character)? or favorites.contains({character})? but it didn't work.)
  2. if the character is already a favorite, make the button change to a button that removes the favorite instead (changing both the function and the button text.)(I have no idea how to do this).
  3. Make an average score of all favorites' each stat. (For example, with your chosen favorites your average speed is xxx and your average strength is xxx).
  4. Last, but not least, favorites list must have up to 3 good characters and 3 bad characters. So, if the good or bad characters in the favorites' list are already 3, user cannot choose another good or bad character as favorite. I also don't know how to proceed with this one.

I'm working in a school project and I found my way through most of it, but I realise I still have things to learn, mostly about object props and how to access to them. Thank you. If anything is not clear, please say so and I will add the required data.

  • To solve problem 1, your `contains` approach was correct, however, you'd need search as `character.id` , you can't compare two objects directly, it will only compare their memory locations, which is always different, use `.find` instead. – tsamridh86 Oct 04 '21 at 01:17
  • If you're able to solve 1, you should be able to solve 2. for question 3, i'll leave you with the hint : `useEffect` and `map` . for question 4 use `find`. – tsamridh86 Oct 04 '21 at 01:19
  • happy coding! this is your assignment, so i don't want to provide the answer directly, figure it out yourself and feel empowered like no other . Here's the link : https://stackoverflow.com/questions/12462318/find-a-value-in-an-array-of-objects-in-javascript this is all the hint you require – tsamridh86 Oct 04 '21 at 01:20
  • if I go as "favorites.contains(favorite.find(id => id === character.id))" it gets me the error: TypeError: favorites.contains is not a function If I go as "favorites.find(id => id === character.id) !== undefined" it still doesn't prevent me for adding it twice. – Amadeo de la Peña Oct 04 '21 at 01:46
  • if you find the element, then you will have to prevent the addition yourself – tsamridh86 Oct 04 '21 at 01:59
  • Yeah I know. I use ternary operator. favorites.contains(favorite.find(id => id === character.id)) ? console.log("item already added") : etc. – Amadeo de la Peña Oct 04 '21 at 02:04
  • `find( savedChar => savedChar.id === character.id )` <- please understand why this works – tsamridh86 Oct 04 '21 at 02:11
  • more importantly, did you figure out how it works? – tsamridh86 Oct 04 '21 at 03:52
  • yeah! I was doing something wrong with ```.find``` , however I did not understand how the same rule applies to the rest of the problems – Amadeo de la Peña Oct 04 '21 at 14:19
  • 1
    Accept the answer, once you've understood everything, and so that it will be helpful for future developers – tsamridh86 Oct 04 '21 at 16:36

1 Answers1

0

So, since you've already figured it out yourself, here is the detailed explanation.

find is a function ( or what fancy developers like to say a higher order function ) available for javascript arrays that accepts a function which must return a boolean value i.e., either true or false.

---Quick detour---

A function which must return a boolean value is called a predicate, and this is exactly what's available in the IDE hints if you hover over find enter image description here

---Detour end---

It accepts multiple parameters, with only the predicate being mandatory, and the rest are optional, i'm skipping all the optional ones, so that's your homework, read the docs or the articles at the end of this answer.

As you can read in the hint itself, it will call the predicate, once for each element in the array, until it can find one which will return true & return the value of the element, undefined otherwise.

Which means : that the first parameter in the predicate is going to be your object and the same predicate will be executed on it for all the elements.

Now observe your solution carefully:

find( savedChar => savedChar.id === character.id )

savedChar is one of the objects in the array, and it needs to be compared with the character object, and id which is the short form of identity will always find it accurately.

Finally, quick answers to your problems.

  1. Use find to see if the character is already available, if yes, simply don't add it in your collection.

  2. This will require you to change your render logic, find if the object is in the favorites and render it differently.

  3. just like find, there is a method called reduce, why don't you give it a shot? but that might be a little difficult, so you can use a simple for loop instead.

  4. find(savedChar => savedChar["good-or-bad"]) <- what would this result? figure it out.

And for more reading material : https://medium.com/swlh/array-helper-methods-in-es6-28fc5e5a5dc9

same but more detailed : https://codeburst.io/learn-and-understand-es6-helpers-easily-d41401184487

tsamridh86
  • 1,480
  • 11
  • 23