0

I'm having a problem with removing an element from a certain array, but it removes the element from BOTH that array and another array that's irrelevant. Does anyone spot the problem, because to me it looks correct and should remove the element, "Beer" from the "nearby.items" array and NOT the "locations_dictionary[0].items" array.

var nearby = {
    "looted": false,
    "items": ["Apple","Rusted Sword","Beer","Bronze Sword","Wooden Sword","Excalibur","Bronze Coin"]
};

const locations_dictionary = [
    {
        "name": "City",
        "items": ["Apple","Rusted Sword","Beer","Bronze Sword","Wooden Sword","Excalibur","Bronze Coin"]
    },
    {
        "name": "Forest",
        "items": ["Apple","Stick","Rusted Sword","Corpse","Rusted Dagger"]
    }
];

function Remove_Item_From_Array(a,v) { //a = array, v = value
    for(i = 0; i < a.length; i++) {
        if(a[i] === v) {
            a.splice(i,1);
        }
    }
}

nearby.items.forEach(function(value,index) {
    if("Beer" == value) {
        Remove_Item_From_Array(nearby.items,"Beer");
        return;
    }
})

console.log('nearby array ---> ' , nearby, '\n locations ---> ', locations_dictionary)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
karel
  • 5,489
  • 46
  • 45
  • 50
Countern
  • 3
  • 2
  • 3
    It sounds like you're getting hung up on references, despite the code in your question not showing reason enough for that behavior. Did you actually define the arrays as you've shown us in your example (hard-coding all the strings), or did you do something like `locations_dictionary[0].items = nearby.items` at some point? – Tyler Roper Feb 17 '19 at 04:19
  • 1
    I don't see it in your code, but this behavior can be encountered when you have a variable which holds an object and another variable which holds a reference to that same object. When this is the case, if you mutate the object which the first variable points to (such as by using splice like you have done), you will also see the change reflected in the second variable since it points to the same object in memory. – Zachary Bennett Feb 17 '19 at 04:22
  • @TylerRoper No, I have reread my code thrice, and there are no lines indicating I have not set the `locations_dictionary[0].items = nearby.items`, but rather the opposite. Is that possibly the cause of the problem? – Countern Feb 17 '19 at 04:23
  • So to clarify, you did `nearby.items = locations_dictionary[0].items`? Because that would in fact cause the behavior you're describing – Khauri Feb 17 '19 at 04:24
  • @ZacharyBennett That might be the reason I'm having the problem. – Countern Feb 17 '19 at 04:25
  • 1
    If you declare an array or object, for example `var a = [1,2,3];`, and then set another variable equal to that, `var b = a;`, your variable `b` is a *reference* to the **same array**. Whether you do `a[0] = 0` or `b[0] = 0`, you're changing the exact same thing. – Tyler Roper Feb 17 '19 at 04:25
  • @KhauriMcClain Yes, I did. Thank you for the pointers. Is there any solutions to what I'm doing? – Countern Feb 17 '19 at 04:25
  • @Countern If you want to have two identical arrays, you can *copy* the first instead of *referencing* it. Check this out: https://stackoverflow.com/questions/7486085/copy-array-by-value – Tyler Roper Feb 17 '19 at 04:26
  • 1
    The code is working fine. **"Beer"** is present in **locations_dictionary[0].items** – Maheer Ali Feb 17 '19 at 04:32
  • Thanks everyone for your responses, especially Bennett, McClain, and Roper. – Countern Feb 17 '19 at 04:39
  • 1
    @Countern Hi! Welcome to StackOverflow. As you noted in comments, you are somewhere doing this `locations_dictionary[0].items = nearby.items`. However, this line is nowhere to be seen in the code snippet provided by you. This is confusing for future readers who might stumble upon this question and do not have time to go through the comments. Please update your code snippet to add that line, if it indeed is there as you claim. – code Feb 17 '19 at 04:43

3 Answers3

1

Your code looks fine. i ran your exact code on JSBin and logged both nearby and locations_dictionary:

[object Object] {
  items: ["Apple", "Rusted Sword", "Bronze Sword", "Wooden Sword", "Excalibur", "Bronze Coin"],
  looted: false
}

[[object Object] {
  items: ["Apple", "Rusted Sword", "Beer", "Bronze Sword", "Wooden Sword", "Excalibur", "Bronze Coin"],
  name: "City"
}, [object Object] {
  items: ["Apple", "Stick", "Rusted Sword", "Corpse", "Rusted Dagger"],
  name: "Forest"
}]

Looks like the items in nearby doesn't have Beer in it, but the first items of locations_dictionary array has it. Maybe the problem isn't with the code.

1

As discussed in the comment section your issue seems to be that nearby.items is pointing to the same array in memory as location_dictionary[0].items.

This means that if you change the array which nearby.items is pointing to in memory, the location_dictionary[0].items array will also be changed (as they are sharing the same array) and vice-versa.

Thus, the solution to this issue would be to create a unique array in memory for nearby.items so that when you change nearby.items it doesn't modify the same array.

You can do this by using the spread syntax:

nearby.items = [...location_dictionary[0]]

This will make it so nearby.items refers to its own unique array in memory, and has no connection/ties to the location_dictionary[0].items array

Here are some examples to help you understand what's going on:

let a = [1, 2, 3]; // create array [1, 2, 3] and store it in memory, make "a" point to this array
let b = a; // make "b" point to the same array in memory that a is pointing to

b[0] = 4; // change index 0 of the array in memory
console.log(a); // change because a and b share the same array
console.log(b); // expected change

Using the spread syntax you can instead create your own unique array:

let a = [1, 2, 3]; // create array [1, 2, 3] and store it in memory, make "a" point to this array
let b = [...a]; // create a new array which has the same contents as "a" in memory

b[0] = 4; // change index 0 of b
console.log(a); // didn't change bcause it has its own unqieu reference
console.log(b); // expected change
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
1

If I understand correctly from the comments, you're trying to modify the nearby.items array to remove "Beer". The problem you were having is that locations_dictionary[0].items was also being modified because you assigned nearby.items using the following code somewhere:

nearby.items = locations_dictionary[0].items

The solution would be to copy the array instead of assigning it.

nearby.items = locations_dictionary[0].items.slice(0)
// or if you're using es6
nearby.items = [...locations_dictionary[0].items]

Another option (or even just in addition to) is to use Array#Filter to filter out the "Beer" string. This actually returns a new copy of the array without modifying the original. So you can assign this to nearby.items or just use it as a separate variable.

let items0 = ["Apple","Rusted Sword","Beer","Bronze Sword","Wooden Sword","Excalibur","Bronze Coin"]

var nearby = {
    "looted": false,
    "items": items0
};

const locations_dictionary = [
    {
        "name": "City",
        "items": items0
    },
    {
        "name": "Forest",
        "items": ["Apple","Stick","Rusted Sword","Corpse","Rusted Dagger"]
    }
];


nearby.items = nearby.items.filter(function(value,index) {
    return value !== "Beer"
})

console.log('nearby array ---> ' , nearby, '\n locations ---> ', locations_dictionary)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Khauri
  • 3,753
  • 1
  • 11
  • 19
  • 1
    If someone is curious why JavaScript behaves like this, further reading can be done at http://jasonjl.me/blog/2014/10/15/javascript/ (JavaScript arrays are "passed by reference") – Norman Breau Feb 17 '19 at 04:57