简体   繁体   English

循环遍历字典以按值的顺序显示键和值

[英]Looping over a dictionary to display key and values in order of a value

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). 我试图循环一个带有for循环的字典,以按其中一个值元素(击球顺序号)的顺序显示键和值。

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. 我需要在for循环中使用逻辑完成此任务, 而不使用lambda或函数。 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! 请帮助我走上正确的轨道并记住我在这里学习,所以欢迎任何有用的批评!

Here's an efficient way since we know there are going to be 9 batters. 这是一种有效的方式,因为我们知道将有9个击球手。

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. 我们所做的就是初始化一个包含9个元素的数组,并使用击球顺序将玩家和统计数据作为元组映射到正确的数组索引。 Then we loop through the array of player and statistics tuples, and print the desired formatted output. 然后我们遍历播放器和统计元组的数组,并打印所需的格式化输出。 This is O(n). 这是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. 这个概念基本上来自Radix排序 ,或者更具体地说,是一个非常简单的计数排序的情况,其中所有频率都是1,而“关键函数”只是从击球顺序中减去1以获得数组索引。

As @PadraicCunningham notes in the comments, this can theoretically be used for any number of batters by using the len function. 正如@PadraicCunningham在评论中指出的那样,理论上这可以通过使用len函数用于任意数量的击球手。

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: 为此,您可以使用sorted()和一个键函数来指定在传递(key, value)元组时如何获取值:

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: 对于你的rays_starters字典,这将产生以下结果:

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列表:

data = [(b[1], p, b[0], b[2]) for p, b in rays_starters.items()]

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: 如果你不能使用min,lambdas,sorted和其他函数调用等手动找到从最低开始播放击球数最低的玩家:

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: 如果击球总是从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

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. 一种非常简单且非常无效的方法是在数组上迭代len(rays_starters)次数,并且每次只打印匹配顺序的结果。

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])

Seems like a better way to handle this would be a (sorted) list of namedtuples 似乎更好的方法来处理这将是一个(排序)的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))

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 另一方面,如果你删除一些玩家,它仍然有效,不像接受的答案:-P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM