Move Items from one List to Another

Hi all, so I have 10 lists named 1,2,3,4,5,6,7,8,9,10, I want items in the lists to be transferred to the next list up when a button is pressed. For example, if I add “stuff” to list 1, then I want “stuff” to be added to list 2 and deleted from list 1, then added to list 3 and deleted from list 2, and so on.

I did this myself using a function but it doesn’t work right. Tell me if you want to see the code.

What is this for?

You use list.pop(index) , but if you are moving multiple pieces of data, you are best “collecting” whom to be moved each frame, and moving them at the end.

Search for python multiDelete()

Search remove multiple items from list python




def multi_delete(list_, args):
    indexes = sorted(list(args), reverse=True)
    for index in indexes:
        del list_[index]
    return list_


Short
“Moving” is pretty simple:

Remove the item from list 1
Add it to list 2


listToMoveFrom.remove("stuff")
listToMoveTo.append("stuff")

Is that what you need?

Details
Here is it at high level (no error handling yet):


def move(lists, item):
    sourceList = findListContainingItem(lists, item)
    destinationList= findNextList(lists, sourceList)
    moveItem(sourceList, destinationList, item)


You would need to search all lists to see where the item is:


def findListContainingItem(lists, itemToLookFor):
    for subList in lists:
        if itemToLookFor in subList:
            return subList

Then find the next list:


def findNextList(lists, list):
    'Error when the list is the last list'
    index = lists.index(list)
    return lists[index+1]

And the move as mentioned above, but separated into an own function:


def moveItem(sourceList, destinationList, itemToMove):
    sourceList.remove(itemToMove)
    destinationList.append(itemToMove)

Demo
All together a runnable demo:

def demonstrateMove():
    lists = [[] for a in range(10)]
    lists[0].append("stuff")
    print(lists)


    for a in range(10):
        move(lists, "stuff")
        print(lists)
    
demonstrateMove()

    
def move(lists, item):
    sourceList = findListContainingItem(lists, item)
    destinationList= findNextList(lists, sourceList)
    moveItem(sourceList, destinationList, item)


def findListContainingItem(lists, itemToLookFor):
    for subList in lists:
        if itemToLookFor in subList:
            return subList
        
def findNextList(lists, previousList):
    'Error when the list is the last list'
    index = lists.index(previousList)
    return lists[index+1]


def moveItem(sourceList, destinationList, itemToMove):
    sourceList.remove(itemToMove)
    destinationList.append(itemToMove)

Remark: This code is not efficient. It should be fine when the list size is just few items (<100). On larger lists you need to think about more efficient data structures.

What is this for?

It is for a game where you have to free a lot of clones from a evil place, you can track there ages, and when they get old enough they can get jobs and raise more money to free more clones (it actually goes up to 18 but I was simplifying it). The lists are age lists and names of the clones are stored in the list of their age (and also the age would change at the end of the in-game year not at the press of a button, again simplifying).

Short
“Moving” is pretty simple:

Remove the item from list 1
Add it to list 2

Code:
listToMoveFrom.remove(“stuff”)
listToMoveTo.append(“stuff”)
Is that what you need?

No, I need to be able to move all items in all lists to the next list up without knowing what is in the list to begin with. so like I said in response to BPR, the lists are ages and the clones names are stored in the list of their age.

so like this:

In the game I buy Bob and Tim, and they are both 2, then I buy Adam who is 4, and Tommy who is 5.

lists represent ages 1 through 10

[, [‘Bob’, ‘Tim’], , [‘Adam’], [‘Tommy’], , , , , ]

Then the year changes and everybody gets a year older.

[, , [‘Bob’, ‘Tim’], , [‘Adam’], [‘Tommy’], , , , ]

Also I tried your demo script and got an error:line 8 in demonstrateMove name ‘move’ is not defined

Lol, then just add a new list as first element :smiley:

Or just have a property in each agent, and have the property advance?

for object in own.scene.objects:
    if "Age" in object:
        object['Age'] +=1
   Year = "Year_" +str(object["Age"]) 
   if object["Age"]==value and Year not in object:
       print(object.name+" is 5 and now can shoot lasers") 
       object["Lasers"] = True
       object[Year] = True

This, O(1) is always the best complexity. And remove the last. Python lists are linked lists if I’m not wrong.

Lol, then just add a new list as first element :smiley:

Sorry, I must not have explained well enough, that won’t work for my situation.

Or just have a property in each agent, and have the property advance?

I think that will work, and it is simpler than what I had. I’ll try to test it tomorrow.

Thank you both!

Using list indices seems like a rather awkward way of tracking the ages of objects. Why not make your own class that tracks the clones’ ages instead?

class Clone:
    def __init__(self, name, age):
        self.name = name
        self.age = age

You can then just store all the clones in a list and iterate through them or use a function to increment their ages when needed.

myClones = [Clone('Bob', 2), Clone('Tim', 2), Clone('Adam', 4), Clone('Tommy', 5)]

def increment_ages(cloneList):
    for clone in cloneList:
        clone.age += 1

increment_ages(myClones)

I would not work with ages at all.

It means you have to update the age with every access as time is going on.

It is much better to store the birthday and calculate the age when needed.


# Bob and Tim, and they are both 2, then I buy Adam who is 4, and Tommy who is 5.
namesByAge = [[], ['Bob', 'Tim'], [], ['Adam'], ['Tommy'], [], [], [], [], []]

print("before:", namesByAge)

# Then the year changes and everybody gets a year older.
namesByAge.insert(0, [])
namesByAge.pop()

print("after: ", namesByAge)

@Monster, that is different than what I was thinking, but I believe it will work, thanks.

@Mobious, good idea, but I’m not very experienced with classes, and although I would like to get better at them, I’m already a bit over schedule on my game and don’t want to run into many problems that I don’t know how to fix.

What’s supposed to happen when you increment the age of clones who are already at the max age? Using Monster’s method, they just get completely removed from the list and discarded. Is that what you want?

With monster method, if you don’t remove them they just increase, all good. You can also trigger some event for all, each, or some of them before removing them. (which would be O(n) for n being the amount of people that are going to die). And this complexity can’t be improved since you require an even for each.

If you’re playing with Ages, like in “Everybody ages equally fast”, then monsters is the only true way. O(1) can’t be beated.

Notice that you can have instances of a class as elements of the list, still sorted by age, but you can also duplicate the references on other data-structures if you want to sort by some other key.

Notice too that O(n log n) is only the fastest complexity for arbitrary keys, in this case they are sorted by age so that doesn’t hold.

EDIT: It seems that python lists are not linked lists, you still get the best performance of all solutions (for being arrays to references) but could be even better. Since the maxium age is a constant though, it’s still O(1). If we don’t limit the age, then it’s O(age) wich is still much better than O(nºelements)

Actually yes, when they have reached the last age(which is really 18), you need to buy them a train ticket to go to the surface(this is under ground by the way), otherwise they get drafted to the military. Either way, they don’t turn 19 while you are tracking them.

@elmeunick9:

With monster method, if you don’t remove them they just increase, all good. You can also trigger some event for all, each, or some of them before removing them. (which would be O(n) for n being the amount of people that are going to die). And this complexity can’t be improved since you require an even for each.

If you’re playing with Ages, like in “Everybody ages equally fast”, then monsters is the only true way. O(1) can’t be beated.

Yep, they all age equally fast, its one of the advantages of having them be clones. They all got the same birthday

Notice that you can have instances of a class as elements of the list, still sorted by age, but you can also duplicate the references on other data-structures if you want to sort by some other key.

Notice too that O(n log n) is only the fastest complexity for arbitrary keys, in this case they are sorted by age so that doesn’t hold.

EDIT: It seems that python lists are not linked lists, you still get the best performance of all solutions (for being arrays to references) but could be even better. Since the maxium age is a constant though, it’s still O(1). If we don’t limit the age, then it’s O(age) wich is still much better than O(nºelements)

OK good, its limited.

I think the more important question is, why do you need the characters grouped by ages?

Do you need fast access to all characters of the same age?
Do you check the age individually (e.g. when leaving the train station) as you have a set of characters of any age?

Well, when they get jobs, I can make is so they get paid different, or get different jobs based on their age, and display the names of all the clones of any age quite easily. But really it just seemed like a good way to keep them organized.

Do you need fast access to all characters of the same age?
Do you check the age individually (e.g. when leaving the train station) as you have a set of characters of any age?

What do you mean by “fast” and “Do you check the age individually”?

Fast means how fast can you find the desired information (e.g. find all characters of a specific category). When you always look for characters of the same age this is fast. If you look for characters with a certain skill set, you need to dig through all of them = slow.

Example: “ leaving the train station”

As far as I see it there is no restriction that characters leaving a train station have to be of the same age. So you get a set of characters with different ages. To place them into your structure by age you have to check each single one what age they are.

When you are happy with the structure you have than it is fine.

OK, thanks for clearing that up. To answer your question, yes I do need fast access to all items of the same list.

The problem you have is basically the keys you use to sort them. To add age to all elements is O(1), but to find the age of one element is O(n). If you store the age inside the elements then getting the age will be O(1), but increase everyone age will be O(n). There is a way, by storing the reference of the list with same ages on each element wich would get you O(k) for finding the age of an element and O(1) to increase them all.

Notice O(k) is much better than O(n) in your case.

In your case I doubt you will have many objects, so I would stick with a simpler solution. (Aka. Anything that works).