Fast Efficient way to transfer an object to another list

Bryan bryanjugglercryptographer at yahoo.com
Fri May 7 17:51:13 EDT 2010


Gabriel Genellina wrote:
> I'd do that in two steps:
>
> def transfer_stock(stock_code, old_list, new_list):
>    # find the indexes to transfer
>    indexes = [i for i,stock in enumerate(old_list)
>               if stock.code==stock_code]
>    # actually transfer them
>    for index in reversed(indexes):
>      stock = old_list[index]
>      new_list.append(stock)
>      del old_list[index]
>    # I would not return anything

The first step -- finding the items -- looks great. The step of adding
items to new_list is just a bit squirly in that it reverse the order
they had in old_list. The last step -- deleting them from old_list --
is a sluggish order n**2 run-time; it can be done in order n. (That's
worst-case; your solution is linear time if either very few elements
get transferred or very few do not get transferred.)

Inspired by your use of list comprehension, and noting the simplicity
of the condition for transferring an item, I suggest the following
compact, order-preserving, linear-time solution:


def transfer_stock(stock_code, old_list, new_list):
    new_list.extend(s for s in old_list if s.code==stock_code)
    old_list[:] = [s for s in old_list if s.code!=stock_code]



#
# Even obviously-correct code deserves testing:
#

from random import choice

class Blurf:
    def __init__(self, code):
        self.code = code

for nitems in range(10):
    for _ in range(17):
        nl_prefix = choice(range(13))
        new_list = [Blurf(3) for _ in range(nl_prefix)]
        old_list = [Blurf(choice([3, 9])) for _ in range(nitems)]
        nitems = len(new_list) + len(old_list)
        original_new_list = new_list[:]
        original_old_list = old_list[:]

        transfer_stock(3, old_list, new_list)

        assert len(old_list) + len(new_list) == nitems
        for n in new_list:
            assert n.code == 3
            assert n in original_new_list or n in original_old_list
            source = original_new_list + original_old_list
            assert new_list == [s for s in source if s in new_list]
        for n in old_list:
            assert n.code != 3
            assert n in original_new_list or n in original_old_list
            assert old_list == [s for s in original_old_list
                    if s in old_list]


--
--Bryan



More information about the Python-list mailing list