Reputation: 75
I am attempting to loop over a dictionary with a for
loop to display keys and values in order of one of the value elements(the batting order number).
I can print the keys and values in the intended format, but I cannot figure out how to get the lines in the correct batting order.
I need to complete this task with logic in a for loop and without the use of lambda or a function. Here is what I have so far:
print ('Rays starters' + "\n")
rays_starters = {
'DeJesus' : ['DH', 6, 299],
'Loney' : ['1B', 4, 222],
'Rivera' : ['C', 9, 194],
'Forsythe' : ['2B', 5, 304],
'Souza Jr' : ['RF', 2, 229],
'Longoria' : ['3B', 3, 282],
'Cabrera' : ['SS', 7, 214],
'Kiermaier' : ['CF', 1, 240],
'Guyer' : ['LF', 8, 274] }
for player in rays_starters:
print (player + str(rays_starters[player]))
print ('\n' + 'Today\'s lineup' + '\n')
for player in rays_starters:
batting_order = rays_starters.get(player)
print('Batting ' + str(batting_order[1]) + ' : ' + str(batting_order[0]) + ' ' + player + ' ,current avg: ' + str(batting_order[2]))
The output should look like this:
Rays starters
DeJesus ['DH', 6, 299]
Loney ['1B', 4, 222]
Rivera ['C', 9, 194]
Forsythe ['2B', 5, 304]
Souza Jr ['RF', 2, 229]
Longoria ['3B', 3, 282]
Cabrera ['SS', 7, 214]
Kiermaier ['CF', 1, 240]
Guyer ['LF', 8, 274]
Today's lineup
Batting 1 : CF Kiermaier ,current avg: 240
Batting 2 : RF Souza Jr ,current avg: 229
Batting 3 : 3B Longoria ,current avg: 282
Batting 4 : 1B Loney ,current avg: 222
Batting 5 : 2B Forsythe ,current avg: 304
Batting 6 : DH DeJesus ,current avg: 299
Batting 7 : SS Cabrera ,current avg: 214
Batting 8 : LF Guyer ,current avg: 274
Batting 9 : C Rivera ,current avg: 194
My output does in fact look exactly like this with the exception of the batting order being out of order. Please help me get on the right track and remember I am trying to learn here so any helpful criticism is welcome!
Upvotes: 4
Views: 164
Reputation: 28596
I'm late to the party, but I wanna add this hack anyway:
>>> for x in {v[1]:'Batting {2} : {1} {0} ,current avg: {3}'.format(k,*v)
for k,v in rays_starters.items()}.values():
print(x)
Batting 1 : CF Kiermaier ,current avg: 240
Batting 2 : RF Souza Jr ,current avg: 229
Batting 3 : 3B Longoria ,current avg: 282
Batting 4 : 1B Loney ,current avg: 222
Batting 5 : 2B Forsythe ,current avg: 304
Batting 6 : DH DeJesus ,current avg: 299
Batting 7 : SS Cabrera ,current avg: 214
Batting 8 : LF Guyer ,current avg: 274
Batting 9 : C Rivera ,current avg: 194
Don't do this, though, it relies on the actual but not guaranteed order of dictionary items. I merely post it for edutainment.
On the other hand, it still works if you remove some of the players, unlike the accepted answer :-P
Upvotes: 0
Reputation: 13869
Here's an efficient way since we know there are going to be 9 batters.
lineup = [None] * 9
for player, stats in rays_starters.items():
lineup[stats[1]-1] = player, stats
print ('\nToday\'s lineup\n')
for player, batting_order in lineup:
print('Batting ' + str(batting_order[1]) + ' : ' + str(batting_order[0]) + ' ' + player + ' ,current avg: ' + str(batting_order[2]))
All we are doing is initializing an array of 9 elements and using the batting order to map the player and stats as a tuple to the correct array index. Then we loop through the array of player and statistics tuples, and print the desired formatted output. This is O(n).
This concept is basically derived from Radix sort, or, more specifically, a very simple case of Counting sort where all the frequences are 1 and the "key function" is just subtracting 1 from the batting order to get an array index.
As @PadraicCunningham notes in the comments, this can theoretically be used for any number of batters by using the len
function.
Upvotes: 4
Reputation: 180401
If you cannot use min, lambdas, sorted and other function calls etc manually find the player with the lowest playing batting number starting from the lowest:
out = []
cp = rays_starters.copy()
# keep going while the dict is not empty
while cp:
mn = float("inf")
it = None
# iterate over the item to find the min each time
# from remaining items
for k, v in cp.items():
if v[1] < mn:
mn = v[1]
it = (k, v)
# append current it k/v pair which has the lowest
# batting number
out.append(it)
# remove the key so we can get the next lowest
del cp[it[0]]
for k,v in out:
print("{} {}".format(k,v))
Output:
Kiermaier ['CF', 1, 240]
Souza Jr ['RF', 2, 229]
Longoria ['3B', 3, 282]
Loney ['1B', 4, 222]
Forsythe ['2B', 5, 304]
DeJesus ['DH', 6, 299]
Cabrera ['SS', 7, 214]
Guyer ['LF', 8, 274]
Rivera ['C', 9, 194]
Or without copying:
out = []
seen = set()
# for every player in the dict
for _ in rays_starters):
mn = float("inf")
it = None
# again get min each time based on the batting number
for k, v in rays_starters.items():
# this time we make sure we have not already used
# the player
if v[1] < mn and k not in seen:
mn = v[1]
it = (k, v)
out.append(it)
# add the name of the player that matches our current min
seen.add(it[0])
for k,v in out:
print("{} {}".format(k,v))
If you can actually sort or use sorted use the batting number as the key and just sort the items:
temp = {v[1]:[k]+v for k, v in rays_starters.items()}
for k ,v in sorted(temp.items()):
print("{} {}".format(v[0], v[1:]))
Kiermaier ['CF', 1, 240]
Souza Jr ['RF', 2, 229]
Longoria ['3B', 3, 282]
Loney ['1B', 4, 222]
Forsythe ['2B', 5, 304]
DeJesus ['DH', 6, 299]
Cabrera ['SS', 7, 214]
Guyer ['LF', 8, 274]
Rivera ['C', 9, 194]
If the batting always starts at 1:
temp = {v[1]:[k]+v for k, v in rays_starters.items()}
for k in range(1,len(rays_starters)+1):
v = temp[k]
print("{} {}".format(v[0], list(v[1:])))
You can unpack to print:
temp = {v[1]:[k]+v for k, v in rays_starters.items()}
for k in range(1,len(rays_starters)+1):
name, nm, btn, avg = temp[k]
print("Batting: {} {} {}, current avg: {}".format(btn, name, nm, avg))
Output:
Batting: 1 Kiermaier CF, current avg: 240
Batting: 2 Souza Jr RF, current avg: 229
Batting: 3 Longoria 3B, current avg: 282
Batting: 4 Loney 1B, current avg: 222
Batting: 5 Forsythe 2B, current avg: 304
Batting: 6 DeJesus DH, current avg: 299
Batting: 7 Cabrera SS, current avg: 214
Batting: 8 Guyer LF, current avg: 274
Batting: 9 Rivera C, current avg: 194
Upvotes: 2
Reputation: 2543
A quite simply and quite ineficcient way of doing this is to iterate len(rays_starters) times over the array and only print the result that matchs the order each time.
for i in range (1, len(rays_starters)+1):
for player in rays_starters:
if rays_starters[player][1] == i:
print('Batting ' + str(rays_starters[player][1]) + ' : ' + \
rays_starters[player][1] + ' ' + player + ' ,current avg: ' + \
rays_starters[player][1])
Upvotes: 2
Reputation: 54183
Seems like a better way to handle this would be a (sorted) list of namedtuples
from collections import namedtuple
Player = namedtuple("Player", ['name', 'position', 'order', 'avg'])
players = [Player(*info) for info in [("DeJesus", "DH", 6, 299),
('Loney', '1B', 4, 222),
...]]
players.sort(key=lambda p: p.order)
for player in players:
print("Batting {p.order} : {p.position} {p.name}, current avg {p.avg}".format(p=p))
Upvotes: 1
Reputation: 387607
Dictionaries do not have an order, so you cannot sort them. You can however iterate over its values in a sorted manner. For this, you can use sorted()
and a key function that specifies how to get the value when passed a (key, value)
tuple:
for player, batting in sorted(rays_starters.items(), key=lambda x: x[1][1]):
print('Batting {1} : {0} {player}, current avg: {2}'.format(*batting, player=player))
For your rays_starters
dictionary, this will yield the following result:
Batting 1 : CF Kiermaier, current avg: 240
Batting 2 : RF Souza Jr, current avg: 229
Batting 3 : 3B Longoria, current avg: 282
Batting 4 : 1B Loney, current avg: 222
Batting 5 : 2B Forsythe, current avg: 304
Batting 6 : DH DeJesus, current avg: 299
Batting 7 : SS Cabrera, current avg: 214
Batting 8 : LF Guyer, current avg: 274
Batting 9 : C Rivera, current avg: 194
If you can’t specify such a key function, you will have to implement the sorting on your own. For this, you can first turn the dictionary into a list first which you then sort. In order to not need a key function, you should construct that list so the value you want to sort by is the first in the list:
data = []
for player, batting in rays_starters.items():
data.append((batting[1], player, batting[0], batting[2]))
# now sort the list
data.sort()
# and iterate and print
for player in data:
print('Batting {0} : {1} {2}, current avg: {3}'.format(*player))
You can also create the data
list using a list comprehension:
data = [(b[1], p, b[0], b[2]) for p, b in rays_starters.items()]
Upvotes: 2