1

I have a really simple algorithm that's meant to sort some 48 numbers into buckets with specific ranges. For example, if my ranges are [0, 16), [16, 32), [32, 48) I would have 3 buckets with 16 integers each.

ds = range(0, 48)
bounds = [[0, 16], [16, 32], [32, 48]]
acd = [[]] * len(bounds)

for d in ds:
    for i in range(0, len(bounds)):
        if bounds[i][0] <= d < bounds[i][1]:
            print("Adding %s to %s" % (d, i))
            acd[i] += [d]

The print statement works as expected, for example it will print "Adding 47 to 2"

However, the array acd which is supposed to contain the buckets, has all 48 elements in all 3 buckets. I'm kind of lost as to why this could be happening since it's such a simple algorithm.

Carpetfizz
  • 8,707
  • 22
  • 85
  • 146

1 Answers1

3

The problem is this line:

acd = [[]] * len(bounds)

acd will contain len(bounds) times the same empty list. You need them to be different lists.

acd = [[] for _ in range(len(bounds))]

The [x] * n shortcut is suitable only when you want multiple copies of the same x.

janos
  • 120,954
  • 29
  • 226
  • 236
  • Never would have guessed, thank you! Will accept when it lets me – Carpetfizz Mar 17 '18 at 20:57
  • 1
    "The [x] * n shortcut is suitable only when x is immutable." eh, or when you want to repeat the same object multiple times. Consider the classic "grouper" recipe: `zip(*[iter(some_iterable)]*n)`. So, like a mutable default argument, there is nothing *inherently wrong* with it if you understand the semantics (and as long as you are willing to agree there is nothing inherently wrong with mutable objects) – juanpa.arrivillaga Mar 17 '18 at 22:14
  • 1
    @Carpetfizz note, it's quite consistent with the concatenation operator: `+`, so `L = [x]; L + L + L == L*3 == [x, x, x]` – juanpa.arrivillaga Mar 17 '18 at 22:17
  • 1
    @juanpa.arrivillaga good point, I was a bit lazy on the wording, kind of counting on other users to call me out on it with something better, so thanks, improved! – janos Mar 17 '18 at 22:29