0

I try to add new property "id" to an array of object. The reson I don't to this in the begining is because first I have to sort the array in a random order. I try to do this with a loop, alse with forEach, but it doesn't work. Why?

    CreateCardList = () => {
        const { cardsAmount } = this.state;
        let halfList = [];
        let card = {};
        for (let i = 0; i < cardsAmount/2; i++) { // choose cards for half of the amount
            card = {
                type: 'hero',
                isHidden: true
            }
            halfList.push(card);
        }
        let entireCardList = [...halfList, ...halfList]; // duplicate the array
        entireCardList.sort((a, b) => 0.5 - Math.random()); // sorting the array in random order
        for (let j = 0; j < entireCardList.length; j++) {
            entireCardList[j].id = j;
        }
        console.log(entireCardList);
    }

In the console I got the below array. If I refrush, the id numbers change but still it is not ordered.

0: {type: "hero", isHidden: true, id: 9}
1: {type: "hero", isHidden: true, id: 7}
2: {type: "hero", isHidden: true, id: 10}
3: {type: "hero", isHidden: true, id: 5}
4: {type: "hero", isHidden: true, id: 11}
5: {type: "hero", isHidden: true, id: 5}
6: {type: "hero", isHidden: true, id: 8}
7: {type: "hero", isHidden: true, id: 7}
8: {type: "hero", isHidden: true, id: 8}
9: {type: "hero", isHidden: true, id: 9}
10: {type: "hero", isHidden: true, id: 10}
11: {type: "hero", isHidden: true, id: 11}
Lior Bar
  • 213
  • 1
  • 4
  • 12

3 Answers3

1

When you make card entireCardList you do not duplicate objects, so you end up with [object1, object2, ... , object1, object2, ...] array. So when you assign id it just overrides values. To fix this you can create copies of objects for second half of the array:

let entireCardList = [...halfList, ...halfList.map(x => ({...x}))]

PS Does not make any sense for me to sort array in random order which contains exactly same elements

Alex
  • 1,724
  • 13
  • 25
  • I do it for create memory cards game. I still don't understand this point. What I should do to fix this? – Lior Bar Aug 07 '19 at 22:09
  • You should create copies of objects for second half of the array. For example like this: `let entireCardList = [...halfList, ...halfList.map(x => ({...x}))];` – Alex Aug 07 '19 at 22:12
  • This solution is problematic. If someone modifies an item in `halfList` the `entireCardList` first part will be modified as well... so I would not relay on this. – V. Sambor Aug 07 '19 at 22:23
  • @V.Sambor Who will modify an item in `halfList`? It is not being returned anywhere and just used as temporary var to create `entireCardList ` – Alex Aug 07 '19 at 22:25
  • How do you know is temporary ? since it is declared in the global scope... – V. Sambor Aug 07 '19 at 22:26
  • You should think that people put snippets here, not the entire code, so what you see is just a part of his code probably... :) – V. Sambor Aug 07 '19 at 22:27
  • @V.Sambor How is it declared in the global scope? I see it declared using `let` inside arrow function – Alex Aug 07 '19 at 22:29
  • by global I ment his component... (it is not nested in some conditions...) – V. Sambor Aug 07 '19 at 22:33
1

Your problem comes from this line: let entireCardList = [...halfList, ...halfList];
You are trying to create a completly new array by thinking that you are duplicating the halfList, but what is instead happening; the spread operator will not create a deep copy of array so it is just shallow copied. And when you assign a id to one item from the list, it is actually assigned to multiple, since they have the same reference.

one solution replace this: let entireCardList = [...halfList, ...halfList]; with:

const firstHalf = JSON.parse(JSON.stringify(halfList));
const secondHalf = JSON.parse(JSON.stringify(halfList));
let entireCardList = [...firstHalf, ...secondHalf];

And it should work as expected :)

Working example:

const cardsAmount = 6
const halfList = [];

for (let i = 0; i < cardsAmount / 2; i++) {
  halfList.push({ type: 'hero', isHidden: true });
}

const firstHalf = JSON.parse(JSON.stringify(halfList));
const secondHalf = JSON.parse(JSON.stringify(halfList));
const entireCardList = [...firstHalf, ...secondHalf];

// If cards are the same, then there is no point in sorting...
entireCardList.sort((a, b) => 0.5 - Math.random());

for (let j = 0; j < entireCardList.length; j++) {
  entireCardList[j].id = j;
}

console.log(entireCardList);
V. Sambor
  • 12,361
  • 6
  • 46
  • 65
  • I think there is no need to deep clone `firstHalf` – Alex Aug 07 '19 at 22:14
  • It works! But still I don't understand what JSON.stringify and JSON.parse do? Can I use something more simple to duplicating like concat function? Example: halfList.concat(halfList) – Lior Bar Aug 07 '19 at 22:15
  • 1
    @liorbar JSON stringify/parse is a way in javascript just to clone things deeply (it means really to provide a new reference in memory) check this out: https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript – V. Sambor Aug 07 '19 at 22:20
  • 1
    @V.Sambor Thanks so much!! You help me a lot with my project. – Lior Bar Aug 07 '19 at 22:26
0

Because you create an array that contains pairs of refs to objects, thats why :)

let entireCardList = [...halfList, ...halfList];

Moyous
  • 1
  • 1