【问题标题】:How can I isolate a Python dictionary from a list for comparison?如何从列表中隔离 Python 字典以进行比较?
【发布时间】:2014-10-30 15:56:55
【问题描述】:

我有一个 Python 函数,它将玩家的姓名和分数作为参数,并确定这是否是玩家的最高分数。它通过将参数与搁置对象进行比较来实现。

搁架应该只存储每个玩家的高分;例如,不应该为名为“Joe”的人评分。

不幸的是,我不知道如何从字典列表(架子)中分离出一个字典,以便与传入的玩家字典进行比较。

这是我的代码:

import shelve
import os


def highscore(player_name, player_score):
    """
    Function to return the high score from our
    persistent storage of score records for a given
    person.
    """
    # Get our working directory
    working_dir = os.getcwd()
    # Create our shelf object for a player
    highscore_fn = os.path.join(working_dir, 'highscore.shelve')
    # Set our player info
    player = {'name': player_name, 'score': player_score}

    with shelve.open(highscore_fn, writeback=True) as shelf:
        # Check if any records exist in the shelf
        if len(shelf) == 0:
            # Assign the shelf to an empty list
            shelf['player_data'] = []
            # Append player data to shelf
            shelf['player_data'].append(player)
            # Current high score for player
            high_score = player.get('score')
        else:
            # Loop through our player data list
            for data in shelf['player_data']:
                # Check to see if we have data for a player
                if player['name'] in data['name']:
                    existing_record = data
                    # Compare the player's new score against previous score
                    if player.get('score') > existing_record.get('score'):
                        high_score = player.get('score')
                        # Update our record for the player
                        existing_record.update(player)
                    else:
                        high_score = existing_record.get('score')
                else:
                    high_score = player.get('score')
                    shelf['player_data'].append(player)

    # Return the high score
    return high_score

任何提示将不胜感激!

【问题讨论】:

  • 你能举一个isolate a dict from the list of dicts (shelf) for comparison against the incoming player dict的例子吗?
  • 你有什么理由使用字典列表而不是字典的字典吗?
  • 另外(完全不相关,但)您应该永远依赖os.getcwd() 为您的应用程序数据计算路径 - “当前工作目录”并不意味着“目录你的代码文件在”,但“用户启动程序时所在的目录”(假设代码的某些部分没有将其更改为其他任何内容......)。
  • 您的搁置中是否包含除player_data dicts 列表之外的其他对象?

标签: python list dictionary shelve


【解决方案1】:

如果您没有其他理由使用 dicts 列表,那么仅使用 dicts 的 dict(甚至是简单的 dict)将大大简化您的代码。假设你的架子看起来像

{
   "user_data": { 
      "joe": {"score": 2999, "name":"joe"}, 
      "walt": {"score": 1784, "name":"walt"}, 
      "bunny": {"score": 87441, "name":"bunny"}, 
      # etc
      },
}

那么您的代码将如下所示:

player = {'name': player_name, 'score': player_score}
high_score = player_score
with shelve.open(highscore_fn, writeback=True) as shelf:
    user_data = shelf["user_data"]
    # Check if any records exist in the shelf
    found = user_data.get(player_name)
    if found:
        if found["score"] < player_score:
            user_data[player_name] = player
        else:
            high_score = found["score"]
    else:
        user_data[player_name] = player
    shelf["user_data"] = user_data

return high_score

注意,如果shelf只包含“user_data”,你可以去掉这个级别,直接将你的dicts存储在shelf本身中。此外,如果您只有分数要保存,您可以将您的 dicts dict 转换为简单的 dict,即:

=> 你的书架:

{
  "joe": : 2999, 
  "walt": 1784, 
  "bunny": 87441, 
  # etc
}

=> 你的代码:

high_score = player_score
with shelve.open(highscore_fn, writeback=True) as shelf:
    # Check if any records exist in the shelf
    found = shelf.get(player_name, 0)
    if found > player_score:
        high_score = found
    else:
        shelf[player_name] = player_score

return player_score

编辑:2.7.3 上的以下代码 JustWorks(tm):

# scores.py
import shelve

DATA = {
    "user_data": { 
        "joe": {"score": 2999, "name":"joe"}, 
        "walt": {"score": 1784, "name":"walt"}, 
        "bunny": {"score": 87441, "name":"bunny"}, 
        # etc
        },
    }


class Score(object):
    def __init__(self, path):
        self.path = path

    def init_data(self, data):
        shelf = shelve.open(self.path)
        shelf["user_data"] = data["user_data"]
        shelf.close()

    def read_data(self):
        d = {}
        shelf = shelve.open(self.path)
        d["user_data"] = shelf["user_data"]
        shelf.close()
        return d

    def highscore(self, name, score):
        player = {'name': name, 'score': score}
        high_score = score
        shelf = shelve.open(self.path)
        user_data = shelf["user_data"]
        found = user_data.get(name)
        if found:
            if found["score"] < score:
                user_data[name] = player
            else:
                high_score = found["score"]
        else:
            user_data[name] = player
        shelf["user_data"] = user_data
        shelf.sync()
        shelf.close()
        return high_score


>>> import scores
>>> s = scores.Score("scores.dat")
>>> s.init_data(scores.DATA)
>>> s.read_data()
{'user_data': {'walt': {'score': 1784, 'name': 'walt'}, 'joe': {'score': 2999, 'name': 'joe'}, 'bunny': {'score': 87441, 'name': 'bunny'}}}
>>> s.highscore("walt", 10000)
10000
>>> s.read_data()
{'user_data': {'walt': {'score': 10000, 'name': 'walt'}, 'joe': {'score': 2999, 'name': 'joe'}, 'bunny': {'score': 87441, 'name': 'bunny'}}}

【讨论】:

  • 所以,这并不是我所需要的,尽管它让我朝着正确的方向思考。如果为同一玩家输入后续分数,则不会存储该玩家的最高分。
  • @PatrickBeeson:第一个示例中确实存在拼写错误和缺失。 FWIW 我不知道您使用的是哪个 Python 版本,但在我这里的版本(2.7.3)上,with shelve.open() 引发“AttributeError:DbfilenameShelf 实例没有属性'exit'”。
【解决方案2】:

我和你玩了一点脚本。它工作得很好,但是当我查看货架上的东西时,我发现:

{ 'player_data' : [ { 'score': 10, 'name': 'joe' }, { 'score': 5, 'name': 'jim'} ] }

它是一个包含 dicts 列表的字典(搁置本身),而它又只有 2 个属性。

在您的代码中很明显,您想要的只是玩家(这里是名称)的属性(这里是 [high]score)。

我的建议是重写它,除非搁置的格式是公共 API 扭结的一部分,以便搁置变为:

{ 'joe': 10, 'jim' : 5 }

或者如果您以后想为每个玩家添加其他属性:

{ 'joe': { 'score': 10}, 'jim' : { 'score': 5} }

这样,一切都变成了:

player = {'name': player_name, 'score': player_score}

with shelve.open(highscore_fn) as shelf:
    high_score = shelf[player_name] if shelf.has_key(player_name) else None
    if (high_score is None) or (high_score < player_score):
        high_score = player_score
        shelf[player_name] = high_score
    shelf.close()

return high_score

这只是 bruno desthuilliers 答案的微小变化,但我测试了 id 和:

  • 它正确地保持并显示每个用户的更高分数
  • 只保留较高分数的版本不需要writeback=true,因为改变的只是货架的顶级元素

【讨论】:

    【解决方案3】:

    已编辑这是解决我的问题的重构代码:

    import shelve
    import os
    
    
    def highscore(name, score):
        """
        Function to return the high score from our
        persistent storage of score records for a given
        person.
        """
        # Get our working directory
        working_dir = os.getcwd()
        # Create our shelf object for a player
        highscore_fn = os.path.join(working_dir, 'highscore.shelve')
        # Open our shelf
        with shelve.open(highscore_fn, writeback=True) as shelf:
            # Check if player exists in shelf
            if name in shelf:
                # Check if score is greater than existing score
                if score > shelf[name]:
                    # Assign our new high score
                    high_score = score
                    # Assign the value of player to our shelf
                    shelf[name] = score
                else:
                    # Existing high score stands for player
                    high_score = shelf[name]
            else:
                # Assign the player to the shelf
                shelf[name] = score
                # Assign the high score to the player score
                high_score = score
    
        return high_score
    

    【讨论】:

      猜你喜欢
      • 2015-03-01
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-23
      相关资源
      最近更新 更多