-1

I'd like to ask you for explain how to correct use the join() function to properly print the elements of list which are dictionaries. I did not find any good tutorial about that. I attached an example to show what I mean:

players_list = [{'name': Tom
                'points': 2},

                {'name': Jerry
                'points': 3},

                {'name': Peter
                'points': 2}
               ]

print("Scores: %s (%d)" % (','.join(player['player_name'], player['player_points'] for player in players_list)))
>> Scores: Tom(2), Jerry(3), Peter(2)

print("There Is a Draw Between %d players: %s " % (len(players_list), ','.join(player['name'] for player in players_list)))
>> There Is a Draw Between 2 players: Tom, Peter

Of course I know that above code does not work. I just don't understand this function.

vaultah
  • 44,105
  • 12
  • 114
  • 143
mathsicist
  • 181
  • 4
  • 15
  • 1
    The second example looks like it ought to work. Have you tried it? What error did you get? – Kevin Nov 12 '15 at 15:39
  • I did and it does not work.I get `string indices must be integers`. But if in your opinion it should work I'll look at it again – mathsicist Nov 12 '15 at 15:50
  • Youhave the keys `'name'` and `'points'` then you try to access `'player_name'` and `'player_points'`, those don't really match. Can you show the exact code you're running? – SuperBiasedMan Nov 12 '15 at 15:51
  • @SuperBiasedMan You're right, I forgot to change keys in second example. Sorry for that. I'm not sure if it is necessary to paste my whole code because I don't care if my code works or not. I'd like to understand how use properly the function. – mathsicist Nov 12 '15 at 16:03
  • Related: [Building up a string using a list of values](http://stackoverflow.com/questions/33681006/building-up-a-string-using-a-list-of-values) – GingerPlusPlus Nov 14 '15 at 14:44

4 Answers4

2

You're not too terribly far off for what you're trying, but I don't think you're understanding all the little pieces that are working together to make your code samples do what they're supposed to do, and there's a few little mistakes (syntax errors) because of this.

For example, your original list of dictionaries should be as follows:

>>> players_list = [
... {'name': 'Tom', 'points': 2},
... {'name': 'Jerry', 'points': 3},
... {'name': 'Paul', 'points': 4}
... ]

Notice the additional quotes around the strings denoting the names of the players. You can then work with this list using Python's fantastic list comprehensions.

>>> [player['name'] for player in players_list]
['Tom', 'Jerry', 'Paul']
>>> [(player['name'], player['points']) for player in players_list]
[('Tom', 2), ('Jerry', 3), ('Paul', 4)]

Although that latter is probably easier to think of as an expression involving a dict method:

>>> list(tuple(player.values()) for player in players_list)
[('Tom', 2), ('Jerry', 3), ('Paul', 4)]

So if you want to print out your first example, "Scores: [name]([points]), [name]([points]), ...", first you need to come up with the list above to feed to your format string. In fact, you can apply the format right in the list comprehension:

>>> ['%s(%s)' % tuple(player.values()) for player in players_list]
['Tom(2)', 'Jerry(3)', 'Paul(4)']

Now you have almost what you want, you just want the title "Scores: " in front and a comma separated string instead of a Python list, hence:

>>> print('Scores: %s' % ', '.join(_))
Scores: Tom(2), Jerry(3), Paul(4)

...where _ is the typical variable in the Python REPL which stores your last result. In other words, all at once:

>>> print('Scores: %s' % ', '.join(list(tuple(player.values()) for player in players_list)))
Scores: Tom(2), Jerry(3), Paul(4)

If you break it down into smaller steps and put it together like this, I think it's easier to see what to do. As far as what join does, it's very simple: it writes a list (an iterable) as a string "joined" by some delimiter. In this case, once you get the list into a suitable format, join's purpose is to write it out as a comma-separated string, by adding ', ' between all the elements.

Applying this logic it should be simpler to get your second example to work properly.


As noted in the comments I got a little lucky here in terms of sorting. In one example, I pointed out the equivalence of player.values() if you really are interested in all the values, so you don't have to name them one by one. However, since dicts in Python are unsorted, sometimes this reverses the point score with the player's name, resulting in:

>>> list(tuple(player.values()) for player in players_list)
[(2, 'Tom'), (3, 'Jerry'), (4, 'Paul')]

For longer dicts, the way to get around this would be to explicitly sort the keys the way you want. Here, though, assuming in the real code there are still only two keys, it is more efficient and readable to 'hard-code' and just call the keys you want by name:

>>> [(player['name'], player['points']) for player in players_list]
[('Tom', 2), ('Jerry', 3), ('Paul', 4)]
>>> print('Scores: %s' % ', '.join([(player['name'], player['points']) for player in players_list]))
Scores: Tom(2), Jerry(3), Paul(4)
Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82
  • I understand it now, thanks. I got one question: why `list(tuple(player.values()) for player in players_list)` print sometimes `['Tom(2)', 'Jerry(3)', 'Paul(4)']` and sometimes `['(2)Tom', '(3)Jerry', '(4)Paul']`? How to control it? – mathsicist Nov 16 '15 at 18:14
  • @mathsicist I removed my long, unwieldy comments in favor of updating the answer. I can talk more about a general solution if you want (for longer dicts with more keys) but for just two keys, I would simply name them explicitly. – Two-Bit Alchemist Nov 16 '15 at 18:37
2

You basically have it correct, however you haven't set up your tuples right. Let me use brackets to show you how Python is evaluating this:

print("Scores: %s (%d)" % (','.join(player['player_name'], (player['player_points'] for player in players_list))))

You see now? The argument to %s is actually player['player_name'], and the argument to %d is (player['player_points'] for player in players_list). What you want is to format each element of the list into a string and join those strings.

So doing the formatting inside your join should look like this:

print("Scores: " + ",".join("%s (%d)" % (player['player_name'], player['player_points'])
                            for player in player_list)

(it's a bit long, so I spread it onto two lines)

SuperBiasedMan
  • 9,814
  • 10
  • 45
  • 73
1

Previous answerers have nicely explained your first print, so I'll focus on second:

print("There Is a Draw Between %d players: %s " % (len(players_list), ','.join(player['name'] for player in players_list)))
>> There Is a Draw Between 2 players: Tom, Peter

First, you need to find a players that have a draw. To do this, you can use collections.Counter to count how many players have given score:

from collections import Counter

scores = Counter(o['points'] for o in players_list) # generator expression

scores is Counter({2: 2, 3: 1}), which means that there are 2 person with 2 points, and 1 person with 3 points.

People with the same score have a draw, so:

scores_that_draws = {k for k, v in scores.items() if v > 1} # set comprehension
# I use set because its `in` implementation is fast

scores_that_draws is {2}, which means that people that have two points have a draw.

We have everything we need. Now we can tell which players have a draw:

# list comprehension, you can use set comprehension as well
draws = [o['name'] for o in players_list if o['points'] in scores_that_draw]

Let's finally write out the desired result:

print('There is draw between: %d players: %s' % (len(draws), ', '.join(draws)))
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
0

I have changed your join, so the player names and scores are concatenated inside the join. The concatenation needs to occur inside the join as you want create one entry for each player. In addition I have also resolved a few syntax errors. I have quoted your player names assuming they are actual strings and not variables and have changed the keys to name and points in the first print.

players_list = [{'name': 'Tom',
                'points': 2},

                {'name': 'Jerry',
                'points': 3},

                {'name': 'Peter',
                'points': 2}
               ]

print ("Scores: %s" % ', '.join("%s(%d)" % (player['name'], player['points']) for player in players_list))
#>> Scores: Tom(2), Jerry(3), Peter(2)

print("There Is a Draw Between %d players: %s " % (len(players_list), ','.join(player['name'] for player in players_list)))
#>> There Is a Draw Between 3 players: Tom,Jerry,Peter 
Alex
  • 21,273
  • 10
  • 61
  • 73