1

tl;dr: how can i delete duplicates from one list, while deleting corresponding entries in a different list?

(note that "class" here is not a class in the programming sense, but in the Dungeons and Dragons sense)

I'm trying to make a function that takes in a list of weights and returns a list of associated strings a number of times equal to the weight. I use random.choice to then select one of these items at random. Here I am removing weights due to multiple possible ways to qualify for each class (multiclassing rules in D&D).

However, I'm running into an error (IndexError: list index out of range) when I try to run this part of the code:

def makeRollable(weights, classNames):
    output = []
    classNames, weights2 = removeDuplicates(classNames, weights)
    for i in range(0, len(weights2)):
        weight = weights2[i]
        for j in range(0, weight):
            output.append(classNames[i])
    return output


def removeDuplicates(names, weights):
    for i in range(len(names)-1, 0, -1):
        for j in range(len(names)-1, i, -1):
            if names[i] == names[j]:
                weights[i] = max(weights[i], weights[j])
                del names[j]
                del weights[j]
    names2, weights2 = names, weights
    return names2, weights2

When I run in debugger, I see that even though the names2 and weights2 have fewer entries in the removeDuplicates fuction, the weights2 list returned to the original size of weights in the makeRollable function.

while the names list has had 5 entries deleted (it was supposed to), the weights list did not. Given that I'm deleting names and weights entries at the same time, I don't see why this should be.

I thought it might be something to do with returning a variable of the same name as one passed to the function, so I made the names2 and weights2 variables to try to fix that, but it didn't seem to help. I was getting the same error with them removed.

if it's helpful, here is a sample data set (there are duplicates for the fighter, magus, and shaman classes because you can qualify for them based on different criteria, and the easiest way I could think of to check for that was to add them multiple times, and then just keep the maximum weight):

classNames = ['Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter', 'Fighter', 'Mage', 'Magus', 'Magus', 'Magus', 'Monk', 'Paladin', 'Ranger', 'Rogue', 'Shaman', 'Shaman', 'Shaman', 'Sorcerer', 'Warlock', 'Wizard']
weights = [4, 2, 0, 0, 4, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0]
  • 5
    Deleting stuff while iterating over a list is a recipe for disaster. What are you trying to accomplish? Almost certainly, there's a better way to go about doing it. – ggorlen Sep 05 '19 at 18:16
  • 1
    Possible duplicate of [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Mihai Chelaru Sep 05 '19 at 18:17
  • When you delete from a list it reindexes itself, so the length of the list is immediately reduced by one. – snakecharmerb Sep 05 '19 at 18:19
  • I am aware that deleting while iterating is dangerous, but if you are iterating backwards, you should be fine (re indexing happens to indexes you've already looked at). This is why I'm using range(len(names)-1, 0, -1). That walks the iteration backwards across the list – daniel brandstetter Sep 05 '19 at 18:23
  • and I did see that question when trying to figure this out myself, but those methods won't work because i need to delete the same indexes from a different list. I am iterating over names, but deleting matching entries from names and weights. – daniel brandstetter Sep 05 '19 at 18:25
  • I can't reproduce the `IndexError`. I'm getting back `['Barbarian', 'Barbarian', 'Barbarian', 'Barbarian', 'Bard', 'Bard', 'Fighter', 'Fighter', 'Fighter', 'Fighter', 'Magus', 'Magus', 'Paladin', 'Paladin', 'Sorcerer', 'Sorcerer', 'Warlock', 'Warlock']`. – Carcigenicate Sep 05 '19 at 19:06
  • " the weights2 list returned to the original size of weights in the makeRollable function. While the names list has had 5 entries deleted (it was supposed to), the weights list did not." None of that seems like it could be happening with the code you've posted. Please show a [mcve] that reproduces the problem. – Carcigenicate Sep 05 '19 at 19:10

1 Answers1

0

Since you've validated that your function is returning the right value, and the other function is not receiving the right input, I think the issue is on how you're dealing with the lists between these functions.

Specifically, you're probably returning a value at some point, but not overwriting the two lists. Basically something like:

a = []
b = []
a = populate_a(a)
b = populate_b(b)

removeDupes(a, b)
# should be
# a, b = removeDupes(a,b)

makeRollable(a, b)

A better long term solution would be to use a dictionary, or if you absolutely need two lists write a class to complete your required functionalities with the two lists. Then just pass this object around and manipulate in the functions using its basic modifiers.

delyeet
  • 168
  • 9