Hey guys,

I'm trying to create a buy and sell program where I have two lists of numbers. Eventually I want to shorten the lists so that the program buys at a lower number, and sells at a higher number, ignoring all other numbers in between.

The solution would be

BuyList = [1,9,11]
SellList = [7,10,12]

I'm having problems with the range in my for loops.

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

length_of_buy_list = []
length_of_sell_list = []
myrange = 0

length_of_buy_list = len(BuyList)
length_of_sell_list = len(SellList)

if length_of_buy_list < length_of_sell_list:
    myrange = length_of_buy_list
elif length_of_buy_list > length_of_sell_list:
    myrange = length_of_sell_list
else:
    myrange = length_of_buy_list #if they are the same length, just pick one.

for x in range(0,myrange-1): #end of range is smaller list so it doesnt go out of range. keep deleting items until everything is in the same range.
    if SellList[x] > BuyList[x]:
        del BuyList[x]

if length_of_buy_list < length_of_sell_list:
    myrange = length_of_buy_list
elif length_of_buy_list > length_of_sell_list:
    myrange = length_of_sell_list
else:
    myrange = length_of_buy_list #if they are the same length, just pick one.

for x in range(0,myrange-1): #end of range is smaller list so it doesnt go out of range. keep deleting items until everything is in the same range.
    if (SellList[x] - BuyList[x]) < 0:
        del SellList[x] #This takes the zero out of my SellList. Delete at the end of the loop otherwise stuff before it will mess up range.

if length_of_buy_list < length_of_sell_list:
    myrange = length_of_buy_list
elif length_of_buy_list > length_of_sell_list:
    myrange = length_of_sell_list
else:
    myrange = length_of_buy_list #if they are the same length, just pick one.


print SellList
print BuyList

Here is a common error I get:

Traceback (most recent call last):
File "C:\Python26\06_June_2009\BuyAndSell\BuyAndSellTest2.py", line 19, in <module>
if SellList[x] > BuyList[x]:
IndexError: list index out of range

I tried to address it by constantly changing the myrange integer to always be appropriate for the length of the smallest list. Any other ideas?

I'm curious why you have the lines

length_of_buy_list = []
length_of_sell_list = []
...
length_of_buy_list = len(BuyList)
length_of_sell_list = len(SellList)

You declared them as empty lists, then changed them to an integer of the list length...

And also, you store these lengths at the beginning but you don't change them throughout the script even though you have things like del BuyList[x] which will subtract from that list's length. Just don't use these variables you made and use len(SellList) and len(BuyList) everywhere else instead. That'll make sure that the real length of the lists is counted.

Do that and it may fix your range error. Tell me what result you get from that.

EDIT:
You can also change your conditionals from

if length_of_buy_list < length_of_sell_list:
    myrange = length_of_buy_list
elif length_of_buy_list > length_of_sell_list:
    myrange = length_of_sell_list
else:
    myrange = length_of_buy_list

to

if length_of_buy_list > length_of_sell_list:
    myrange = length_of_sell_list
else:
    myrange = length_of_buy_list

because that sets "myrange" to the length of the buy list if its length is less than or equal to the sell list's length. Just a cleaner looking way of writing it.

Not quite sure what you want, but maybe function zip() will help:

buy_list = [1,2,3,4,9,11,77,99]
sell_list = [0,7,8,10,12,15]

# removes the excess items of the longer list
buy_sell = zip(buy_list, sell_list)

print buy_sell

for buy, sell in buy_sell:
    print buy, sell

"""
my display -->
[(1, 0), (2, 7), (3, 8), (4, 10), (9, 12), (11, 15)]
1 0
2 7
3 8
4 10
9 12
11 15

"""

Thanks shadwickman. I made some changes and I'm still getting the same error. Here is a simpler version of it.

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

myrange = 0

if len(BuyList) < len(SellList):
    myrange = len(BuyList)
else:
    myrange = len(SellList) 

for x in range(0,myrange-1): 
    if SellList[x] > BuyList[x]:
        del BuyList[x]

    if len(BuyList) < len(SellList):
        myrange = len(BuyList)
    else:
        myrange = len(SellList)

Traceback (most recent call last):
File "C:\Python26\06_June_2009\BuyAndSell\BuyAndSellTest2.py", line 12, in <module>
if SellList[x] > BuyList[x]:
IndexError: list index out of range

The problem only arises when I delete an item from the BuyList or SellList. I know this changes the range but I thought I had accounted for that by changing the range at every point. Any ideas?

Actually, I hadn't realized it before but no matter what, your range will go to the pre-set length, yet you're removing items from the list, which is shortening it to less than that pre-set range. Changing the range inside the for loop has no effect either.
This will allow you to adjust the range inside the loop:

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

myrange = 0

if len(BuyList) < len(SellList):
    myrange = len(BuyList)
else:
    myrange = len(SellList) 

x = 0
while x < myrange:
    if SellList[x] > BuyList[x]:
        del BuyList[x]
        myrange -= 1
    x += 1

print BuyList
print SellList

"""
Output:
[1, 3, 9, 11]
[0, 7, 8, 10, 12, 15]
"""

I'm still not 100% sure what you're trying to achieve with this code... unless you want it to assign the biggest "sell" index possible to each "buy" index? So there is the biggest difference between indices of the two lists?

Anyways, you should look at Ene Uran's code because that may be what you're looking for, as it looks close to what you want and it's a nice, clean-looking solution.

Thanks Ene. But I'm trying to get the low numbers in the buy list and attach it to the first available number greater than that low number in the sell list.

So the program should:

Buy at period 1
Sell at period 7

Buy at period 9
Sell at period 10

Buy at period 11
Sell at period 12

The condition is that you can only hold one buy at a time. Until you sell it, you cannot hold another buy. And you want to buy on the first available date you can buy, which is the first available item in the list.

Thanks Ene. But I'm trying to get the low numbers in the buy list and attach it to the first available number greater than that low number in the sell list.

So then why isn't this the solution:
(buy:sell)
1:7, 2:8, 3:10, 4:12, 9:15

That takes the low numbers in the buy list and attaches them to higher numbers in the sell list.

In your solution, you only listed 1:7, 9:10, 11:12. What happened to the "low numbers" of the buy list, as in 2, 3, and 4?

Shadwickman,

I'm trying to continue the looped function so that the 3 in the BuyList is deleted as well. Since 7 is > 3, 3 should be deleted too.

I need to create another delete function to delete items in the sell list.

my goal is to reduce the list to

[1,3,9] for the BuyList and
[7,10,12] for the SellList

Your code is a good start. Maybe i'll nest the while loop in a for loop"?

So then why isn't this the solution:
(buy:sell)
1:7, 2:8, 3:10, 4:12, 9:15

That takes the low numbers in the buy list and attaches them to higher numbers in the sell list.

In your solution, you only listed 1:7, 9:10, 11:12. What happened to the "low numbers" of the buy list, as in 2, 3, and 4?

The numbers in the lists are supposed to correspond to time period. Think of them as dates.

2,3,4 should be deleted in the Buy List

Because you use your buy ticket only one at a time. So you buy 1. Since 0 is a sell signal before period 1, you cannot go back in time to sell it, so delete 0.

You buy 1 and use your ticket until you can sell at a number higher than 1, which is 7. Since 7 is higher than 2,3,4, you delete them. You already used your ticket to buy 1. You cannot trade your ticket to buy 2. And trade it again to buy 3. You have to wait till you hit Day 7 to sell. So you can't buy on day 1, day 2, day 3, and day 4. You can only buy once until you sell it, then you can buy again at a subsequent date.

Ok, that makes more sense once you said that they correspond to time periods. Before I just couldn't see a logical pattern to what you were matching up.

This code works, but it's kinda messy and hacked together. Not the best option but you can modify it from here. BuyResult and SellResult are the resulting lists with the correct output.

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

BuyResult = []
# if SellResult don't contain something to start,
# then the 'SellResult[-1] < bn' will throw an error.
SellResult = [0]

for bn in BuyList:
    if SellResult[-1] < bn:
        for sn in SellList:
            if sn > bn:
                BuyResult.append(bn)
                SellResult.append(sn)
                break
# remove that starting 0 from SellResult
SellResult = SellResult[1:]

"""
My result:
1:7, 9:10, 11:12
"""

Tell me if you need clarification for the code.

Thanks! That's exactly what I was looking for. I was thinking of moving it into separate lists as well but worried that it would be an extra step.

I'm still not entirely sure why sell result cannot start as an empty list. And why we add and then delete a zero. I'll play with it and figure it out. Thanks.

I'm still not entirely sure why sell result cannot start as an empty list. And why we add and then delete a zero. I'll play with it and figure it out. Thanks.

I have the line if SellResult[-1] < bn inside the BuyList for loop, because that way it will only cycle through the SellList to compare the current buy value IF the current buy value is more than the previous sell value (SellResult[-1] = last number in SellResult).
If SellResult starts as an empty list, then calling the last index of it will result in an error of "list index out of range". All I did was start it off with a zero so that this if statement wouldn't cause errors with the SellResult right off the bat, then I just removed that zero at the end.
You can write it so that you don't need to start SellResult off with a value in it, but I did just so the code would look simpler.

Here's that other way with SellResult starting off blank:

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

BuyResult = []
SellResult = []


def cycleSellList(bn):
    global BuyResult, SellResult
    for sn in SellList:
        if sn > bn:
            BuyResult.append(bn)
            SellResult.append(sn)
            break
    

for bn in BuyList:
    if SellResult:  # if it contains values
        if SellResult[-1] < bn:  # last number in it < bn
            cycleSellList(bn)
    else:  # no values in SellResult yet.
        cycleSellList(bn)
"""
My result:
1:7, 9:10, 11:12
"""

Or if you don't want to use global variables:

BuyList = [1,2,3,4,9,11]
SellList = [0,7,8,10,12,15]

BuyResult = []
SellResult = []


def cycleSellList(bn):
    for sn in SellList:
        if sn > bn:
            return sn
    

for bn in BuyList:
    sn = None  # originally, no matching sell number
    
    if SellResult:  # if it contains values
        if SellResult[-1] < bn:  # last number in it < bn
            sn = cycleSellList(bn)
    else:  # no values in SellResult yet.
        sn = cycleSellList(bn)
    
    if sn != None:  # if it is something other than None
        BuyResult.append(bn)
        SellResult.append(sn)
"""
My result:
1:7, 9:10, 11:12
"""

As you can see, it looks simpler if you just don't take into account that SellResult could either be blank OR have values. That's why I started it off with zero and then removed that first zero at the end.

This article has been dead for over six months. Start a new discussion instead.