1

I have code that looks like:

Loop that appends player names to a list called playerlist
print(playerlist)
lineuplist.append(playerlist)

The print statement ends up printing a list that looks like:

...
['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Pau Gasol', 'Paul Millsap', 'Chandler Parsons', 'Kevin Durant']
['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Serge Ibaka', 'Pau Gasol', 'Kevin Durant', 'Chandler Parsons']
['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Serge Ibaka', 'Pau Gasol', 'Chandler Parsons', 'Kevin Durant']
['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Paul Millsap', 'Pau Gasol', 'Kevin Durant', 'Chandler Parsons']
...

I want my output to be a list of those lists, ie:

[['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Pau Gasol', 'Paul Millsap', 'Chandler Parsons', 'Kevin Durant'],     ['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Serge Ibaka', 'Pau Gasol', 'Kevin Durant', 'Chandler Parsons'], ['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Serge Ibaka', 'Pau Gasol', 'Chandler Parsons', 'Kevin Durant'],     ['Omer Asik', 'Jordan Farmar', 'Patrick Beverley', 'Kyle Korver', 'Kent Bazemore', 'Paul Millsap', 'Pau Gasol', 'Kevin Durant', 'Chandler Parsons']]

However, all I get is this:

print(lineuplist)
[[], [], [], [], []]

Not really sure where I'm going wrong, so any help is appreciated.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • 1
    You need to be more specific on how you're building those lists in the loop. – Paulo Bu Mar 14 '14 at 12:16
  • Updated with more code. Like I said, when i go to do print(playerlist), the output is fine. It's only when I go to append it to lineuplist does it not work correctly. –  Mar 14 '14 at 12:18
  • 3
    that's really gnarly. – Russia Must Remove Putin Mar 14 '14 at 12:19
  • 3
    you're probably re-using the same list. try `lineuplist.append(list(playerlist))` to add a copy. – mata Mar 14 '14 at 12:19
  • 1
    wow! an O(n^9) algorithm – wim Mar 14 '14 at 12:20
  • Yeah I know ... It's a quick prototype for something and it's the best solution I came up with so far. Like I said, my output for print(playerlist) is perfect, it's only when I go to append it does it not work correctly. –  Mar 14 '14 at 12:20
  • I'm 98.5% sure you are reinventing the wheel here. What are those, all combinations of players? (Edit: Actually it looks more like permutations. Is this what you want?) – tobias_k Mar 14 '14 at 12:21
  • @tobias_k lol how do you find `98.5%`? – zhangxaochen Mar 14 '14 at 12:21
  • @zhangxaochen they're in the 91% of the population who make up 67.3% of the statistics on the spot :p – Jon Clements Mar 14 '14 at 12:49

2 Answers2

3

When you append the list into your main list, you're actually appending a pointer to that original list. Python lists are mutable, and when you change them, you change them wherever you have a pointer to them.

If you append a copy of them, you can avoid this being an issue, but you'll waste memory, so it's important to have a good reason to copy them.

Here's an example of this behavior:

>>> l = list('abc')
>>> m = [l.copy()]
>>> m
[['a', 'b', 'c']]
>>> l.remove('a')
>>> m
[['a', 'b', 'c']]
>>> l
['b', 'c']

So what you could do is this:

lineuplist.append(playerlist.copy())

instead of this:

lineuplist.append(playerlist)
Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • There should be an addendum to this about scope. If for example you have defined `lineups` outside of the loop scope, and `playerlist` **inside it** and do not manipulate `playerlist` inside the scope of the loop beyond assigning it to some value before you do the append, then it will do what you expect because `playerlist` is a new list every iteration of the list. If, however, `playerlist` is defined **outside** the scope of the the loop, then you will get the behavior described by the OP because every iteration of the loop is operating on the same `playerlist` – aruisdante Mar 14 '14 at 12:56
1

The actual problem with the content of the lists disappearing has already been solved in the other answer, however I want to note that you can make your code a whole lot simpler.

If I understand the code (now removed from the question) correctly, you are looking for combinations of players forming a legal lineup for a team whose combined salary is within certain bounds. The team needs one player from the C group (captain?), and 2 from each of the PG, SG, PF, and SF groups.

You can use the itertools module for this, particularly product and combinations.

from itertools import product, combinations
player_combinations = product(combinations(C, 1), 
                              combinations(PG, 2),
                              combinations(SG, 2),
                              combinations(PF, 2),
                              combinations(SF, 2))

(Update: This returns nested lists of tuples, so you need to flatten it first. You can use sum for this.)

player_combinations = (sum(pc, ()) for pc in player_combinations)

The result is an iterator with all the combinations of players (the entire objects, not just the names). Now you can find the teams that satisfy the salary criterion in just a single loop and extract their names:

lineuplist = []
for players in player_combinations:
    salary = sum(player[5] for player in players)
    if salarycap - undersalary <= salary <= salarycap:
        names = [player[1] for player in players]
        lineuplist.append(names)
tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • I was just about to post a link to [permutations](http://docs.python.org/2/library/itertools.html#itertools.permutations) for getting all subsets of a given size from some larger list. – aruisdante Mar 14 '14 at 13:05
  • salary = sum(player[5] for player in players) IndexError: tuple index out of range I'm getting that as an error when I try to run that last block of code. –  Mar 18 '14 at 12:48
  • 1
    Well, you used e.g. `salary += int(n4[5])` to get the salary. Did the format of the player lines change since then? – tobias_k Mar 18 '14 at 13:00
  • I actually just changed it so its in index 2. But I adjusted the code to account for that. –  Mar 18 '14 at 13:01
  • @Tobias_k I noticed when I tried `for player in players: print(str(player) + "\n")` it prints out `(['SF', 'Mike Dunleavy', '5000'], ['SF', 'Evan Turner', '4600']) (['C', 'Al Jefferson', '9700'],) (['PG', 'Chris Paul', '9400'], ['PG', 'Russell Westbrook', '8900']) (['SG', 'Eric Bledsoe', '7300'], ['SG', 'Vince Carter', '5400'])` which seems like there's two entries in one line? –  Mar 18 '14 at 13:02
  • I also get this too: ` salary = sum(player[2] for player in players) TypeError: unsupported operand type(s) for +: 'int' and 'str'` –  Mar 18 '14 at 13:06
  • 1
    @Wilson Did you use the `sum` line between the two code blocks to flatten the tuples? About the type error: If salary is a string, you have to convert it to int first, e.g. `sum(int(player[5]) for player in players)` – tobias_k Mar 18 '14 at 13:11
  • @tobias_k it does seem to be a problem that it calculates the salaries based on the tuple of the 2 positions, ie it does c, then pg, then sg, as I showed above when I printed player. –  Mar 18 '14 at 13:22
  • Actually updated my other question so it's easier for you to see. I changed the code now and it works. [link](http://stackoverflow.com/questions/22479267/large-loop-nest-design-anyway-to-improve-speed/22480903#22480903) –  Mar 18 '14 at 13:30