1

Apologies if I explain something wrong or use the wrong wording, my programmer vocabulary isn't the best. If anyone understands my problem and has better ways of explaining it feel free to do so. I have a problem similar to a problem here. I want to remove items from a list that occur in another list. But one list will have strings that reference the variable "name" within class objects.

class sword:
    name = 'swordName'

class bow:
    name = 'bowName'

class axe:
    name = 'axeName'

inventory = [sword, bow, sword, axe]
select = ['bowName', 'swordName']

I want to be able to create a list "selectedItems" with the class objects out of inventory based off of the strings in "select" that are equal to the "name" of the class objects. It also needs to work if "inventory" and "select" both have duplicates in them.

Output:

>> inventory = [bow, axe]    
>> selectedItems = [bow, sword]

One other thing I would like the program to ignore if there are more "name"s in select than there are corresponding class objects in "inventory", and to ignore if a string in "select" has no corresponding class objects.

For example, if "inventory" is [sword, axe] and "select" is ['bowName', 'non-existent', 'axeName'], the result is that "inventory" is [sword] and "selectedItems" is [axe].

A simple way of explaining this is that select will take from inventory, but if select can't take from inventory nothing happens.

Grape Dragon
  • 76
  • 2
  • 9

2 Answers2

1
selectedItems = list()
# make a new list of the names of the objects in the inventory
# inventory and inventory names have the same index for the same item
inventory_names = [x.name for x in inventory]

for s in select:
    if s in inventory_names:
        index = inventory_names.index(s)
        inventory_names.pop(index)
        selectedItems.append(inventory.pop(index))
richie
  • 181
  • 5
1

You may make base class with magic methods __eq__ and __hash__ which can allow you to manage comparing your objects as you want:

class BaseItem:

    name = None

    def __init__(self):
        self.__name = self.name

    def __eq__(self, other):
        return self.__name == other

    def __hash__(self):
        return id(self.__name)

    def __repr__(self):
        return f"'{self.__name}'"


class Sword(BaseItem):

    name = "swordName"


class Bow(BaseItem):

    name = "bowName"


class Axe(BaseItem):

    name = "axeName"


inventory = [Sword(), Bow()]
select = ["swordName", "bowName", "axeName", "swordName", "bowName"]

# casting lists into sets and getting difference between them
result = set(inventory) - set(select)
print(result)  # output {'swordName', 'bowName'}

eq - actually is unused here but i added that you can compare your objects with strings, lists etc:

Sword() in ["swordName"] # true
Sword() in ["bowName"] # false
Sword() == "swordName" # true
Sword() == "bowName" # false

hash - need to comparing two objects, actually it use for getting difference between two sets

repr - it is not really required method, it needs just for pretty displaying of objects

Nikita Zhuikov
  • 1,012
  • 8
  • 11
  • Very well put together answer, it helps a lot. The one problem is the use of set, it deletes duplicates and the output is not what it needs to be when there are duplicate items in the inventory, such as `inventory = [Sword(), Sword()]` and say `select = ["swordName", "swordName", "bowName"]. Where result should be `["swordName, swordName]` This only is a problem with `result = set(inventory) - set(select)` and I can find a way around that easily. The code does not exclude duplicates, as I falsely stated before, it excludes items in select where they can't take from inventory. Thanks again. – Grape Dragon Apr 30 '21 at 16:33