0

I'm attempting to sort some values into a dictionary of lists using string prefixes. Here is the basic code I am running:

values = ["a_one", "a_two", "b_three", "b_four", "c_five", "c_six"]
value_groups = {"a": [],
                "b": [],
                "c": []}

for value in values:
    for prefix in value_groups.keys():
        if value.startswith(prefix):
            value_groups[prefix].append(value)
            break

The desired, and actual, output of this code is:

value_groups = {"a": ["a_one", "a_two"],
                "b": ["b_three", "b_four"],
                "c": ["c_five", "c_six"]}

So the code above works as-is.

My problem arises when I initialize the lists within value_groups with one or more strings. In this case, every value in values gets appended to every list within value_groups. Non-functional code below:

values = ["a_one", "a_two", "b_three", "b_four", "c_five", "c_six"]
# ---START OF EDITED CODE---
initial_list = ["x", "y", "z"]
value_groups = {"a": initial_list,
                "b": initial_list,
                "c": initial_list}
# ---END OF EDITED CODE---

for value in values:
    for prefix in value_groups.keys():
        if value.startswith(prefix):
            value_groups[prefix].append(value)
            break

The desired output of this code would be:

value_groups = {"a": ["x", "y", "z", "a_one", "a_two"],
                "b": ["x", "y", "z", "b_three", "b_four"],
                "c": ["x", "y", "z", "c_five", "c_six"]}

But instead, I am getting three identical lists within value_groups:

value_groups = {"a": ["x", "y", "z", "a_one", "a_two",
                      "b_three", "b_four", "c_five", "c_six"], 
                "b": ["x", "y", "z", "a_one", "a_two",
                      "b_three", "b_four", "c_five", "c_six"], 
                "c": ["x", "y", "z", "a_one", "a_two",
                      "b_three", "b_four", "c_five", "c_six"]}

My intuition (and preliminary Stack Overflow research) is that there is some sort of memory referencing mechanism that I am running afoul of, but I am not quite sure what it is. Anyone out there able to explain it to me? (if that is, indeed, the problem...)

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
ChefPaul92
  • 33
  • 1
  • 8
  • 2
    That behaviour does not happen with the code you've posted. – jonrsharpe Sep 13 '22 at 13:31
  • Did the code run as expected for you? – ChefPaul92 Sep 13 '22 at 13:32
  • 3
    I'm pretty certain that's not how you're defining `value_groups`. What you've probably done is something like `value_groups = {"a": some_list, "b": some_list, "c": some_list}` where `some_list` was previously defined. If that's the case, every key in the dict refers to *the same list*. A fix would be to make copies of `some_list` with an empty slice: `{"a": some_list[:], "b": some_list[:], "c": some_list[:]}` – Steven Rumbalski Sep 13 '22 at 13:33
  • 1
    Run it and see! You're maybe using fromkeys, per e.g. https://stackoverflow.com/q/8174723/3001761 – jonrsharpe Sep 13 '22 at 13:35
  • 1
    @StevenRumbalski, yep, that was the problem. Thanks for the answer and for correctly quessing that I did not properly translate my code to here. – ChefPaul92 Sep 13 '22 at 13:36
  • The question received upvotes as well (probably after the fix). An upvote is worth 5x as much as a downvote in terms of reputation. – CherryDT Sep 13 '22 at 13:59

1 Answers1

3
value_groups = {"a": ["x", "y", "z"],
                "b": ["x", "y", "z"],
                "c": ["x", "y", "z"]}

I'm pretty certain that's not how you're defining value_groups. What you've probably done is something like this (where some_list was previously defined):

some_list = ["x", "y", "z"]
value_groups = {"a": some_list, 
                "b": some_list, 
                "c": some_list}   

If that's the case, every key in the dict refers to the same list. A fix would be to make copies of some_list using some_list.copy() (or by copying with an empty slice some_list[:]):

some_list = ["x", "y", "z"]
value_groups = {"a": some_list.copy(), 
                "b": some_list.copy(), 
                "c": some_list.copy()}
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
  • 2
    Good job intuiting the actual problem. I was looking at the OP's posting and thought "wait a minute! Python doesn't assume initializing lists with the same constant data means they are the same list!" Good job reading between the lines. I've had to do that occasionally on SO when the OP doesn't actually test their sample code to ensure it exhibits the problem behavior. – RufusVS Sep 13 '22 at 13:42
  • 1
    You can also use `some_list.copy()` – RufusVS Sep 13 '22 at 13:43
  • 2
    Sorry for the noob boo-boo of not testing the sample code :( – ChefPaul92 Sep 13 '22 at 13:46
  • 2
    @ChefPaul92 It's not just a noob problem. I'm no noob in Python, but I've been known to quick type or edit a bit of code without testing it. (More than once). – RufusVS Sep 13 '22 at 14:02