【问题标题】:Assigning multiple values to dictionary keys from a file in Python 3从 Python 3 中的文件为字典键分配多个值
【发布时间】:2017-04-03 07:44:18
【问题描述】:

我对 Python 还很陌生,但我还没有找到这个特定问题的答案。 我正在编写一个简单的推荐程序,我需要一个字典,其中美食是键,餐厅名称是值。在某些情况下,我必须拆分几个菜系名称的字符串,并确保将具有相同菜系的所有其他餐厅(值)分配给相同的菜系(键)。这是文件的一部分:

Georgie Porgie
87%
$$$
Canadian, Pub Food

Queen St. Cafe
82%
$
Malaysian, Thai

Mexican Grill
85%
$$
Mexican

Deep Fried Everything
52%
$
Pub Food

所以它只是第一个和最后一个具有相同菜肴的菜肴,但文件后面还有更多。 这是我的代码:

def new(file):
    file = "/.../Restaurants.txt"
    d = {}
    key = []
    with open(file) as file:
        lines = file.readlines()

    for i in range(len(lines)):
        if i % 5 == 0:
            if "," not in lines[i + 3]:
                d[lines[i + 3].strip()] = [lines[i].strip()]
            else:
                key += (lines[i + 3].strip().split(', '))
                for j in key:
                    if j not in d:
                        d[j] = [lines[i].strip()]
                    else:
                        d[j].append(lines[i].strip())
    return d

它打印了所有的键和值,但它没有将两个值分配给它应该分配的同一个键。此外,使用最后一个“else”语句,第二家餐厅被分配给错误的键作为第二个值。这不应该发生。我将不胜感激任何 cmets 或帮助。

【问题讨论】:

    标签: python-3.x dictionary


    【解决方案1】:

    在只有一个类别的情况下,您不检查键是否在字典中。您应该像在多个类别的情况下一样执行此操作,然后它就可以正常工作了。

    我不知道为什么当你有一个文件然后被覆盖时你有一个文件作为参数。

    此外,您应该为每个结果创建“键”,而不是 +=(将其添加到现有的“键”中

    当您检查 j 是否在字典中时,干净的方法是检查 j 是否在键中 (d.keys())

    def new(file):
        file = "/.../Restaurants.txt"
        d = {}
        key = []
        with open(file) as file:
            lines = file.readlines()
    
        for i in range(len(lines)):
            if i % 5 == 0:
                if "," not in lines[i + 3]:
                    if lines[i + 3] not in d.keys():
                        d[lines[i + 3].strip()] = [lines[i].strip()]
                    else:
                        d[lines[i + 3]].append(lines[i].strip())
    
                else:
                    key = (lines[i + 3].strip().split(', '))
                    for j in key:
                        if j not in d.keys():
                            d[j] = [lines[i].strip()]
                        else:
                            d[j].append(lines[i].strip())
        return d
    

    【讨论】:

      【解决方案2】:

      通常,我发现如果您为字典键使用名称,以后处理它们可能会更容易。

      在下面的示例中,我返回了一系列字典,每个餐厅都有一个。我还将处理值的功能包装在一个名为 add_value() 的方法中,以使代码更具可读性。

      在我的示例中,我使用编解码器对值进行解码。虽然不是必需的,但根据您正在处理的字符,它可能很有用。我还使用 itertools 来读取带有迭代器的文件行。同样,根据具体情况没有必要,但如果您正在处理非常大的文件,可能会很有用。

      import copy, itertools, codecs
      
      class RestaurantListParser(object):
      
          file_name = "restaurants.txt"
      
          base_item = {
              "_type": "undefined",
              "_fields": {
                  "name": "undefined",
                  "nationality": "undefined",
                  "rating": "undefined",
                  "pricing": "undefined",
              }
          }
      
      
          def add_value(self, formatted_item, field_name, field_value):
      
              if isinstance(field_value, basestring):
                  # handle encoding, strip, process the values as you need.
                  field_value = codecs.encode(field_value, 'utf-8').strip()
                  formatted_item["_fields"][field_name] = field_value
              else:
                  print 'Error parsing field "%s", with value: %s' % (field_name, field_value)
      
      
          def generator(self, file_name):
      
              with open(file_name) as file:
      
                  while True:
                      lines = tuple(itertools.islice(file, 5))
                      if not lines: break
      
      
                      # Initialize our dictionary for this item
                      formatted_item = copy.deepcopy(self.base_item)
      
                      if "," not in lines[3]:
                          formatted_item['_type'] = lines[3].strip()
                      else:
                          formatted_item['_type'] = lines[3].split(',')[1].strip()
                          self.add_value(formatted_item, 'nationality', lines[3].split(',')[0])
      
                      self.add_value(formatted_item, 'name', lines[0])
                      self.add_value(formatted_item, 'rating', lines[1])
                      self.add_value(formatted_item, 'pricing', lines[2])
      
                      yield formatted_item
      
          def split_by_type(self):
      
              d = {}
              for restaurant in self.generator(self.file_name):
                  if restaurant['_type'] not in d:
                      d[restaurant['_type']] = [restaurant['_fields']]
                  else:
                      d[restaurant['_type']] += [restaurant['_fields']]
      
              return d
      

      然后,如果你运行:

      p = RestaurantListParser()
      print p.split_by_type()
      

      你应该得到:

      {
          'Mexican': [{
              'name': 'Mexican Grill',
              'nationality': 'undefined',
              'pricing': '$$',
              'rating': '85%'
          }],
          'Pub Food': [{
              'name': 'Georgie Porgie',
              'nationality': 'Canadian',
              'pricing': '$$$',
              'rating': '87%'
          }, {
              'name': 'Deep Fried Everything',
              'nationality': 'undefined',
              'pricing': '$',
              'rating': '52%'
          }],
          'Thai': [{
              'name': 'Queen St. Cafe',
              'nationality': 'Malaysian',
              'pricing': '$',
              'rating': '82%'
          }]
      }
      

      您的解决方案很简单,所以没关系。我只想提几个当我想到这类问题时想到的想法。

      【讨论】:

        【解决方案3】:

        这是另一个例子,使用defaultdictsplit 来简化事情。

        from collections import defaultdict
        
        record_keys = ['name', 'rating', 'price', 'cuisine']
        
        
        def load(file):
            with open(file) as file:
                data = file.read()
        
            restaurants = []
            # chop up input on each blank line (2 newlines in a row) 
            for record in data.split("\n\n"):
                fields = record.split("\n")
        
                # build a dictionary by zipping together the fixed set
                # of field names and the values from this particular record
                restaurant = dict(zip(record_keys, fields))
        
                # split chops apart the type cuisine on comma, then _.strip()
                # removes any leading/trailing whitespace on each type of cuisine 
                restaurant['cuisine'] = [_.strip() for _ in restaurant['cuisine'].split(",")]
                restaurants.append(restaurant)
        
            return restaurants
        
        
        def build_index(database, key, value):
            index = defaultdict(set)
            for record in database:
                for v in record.get(key, []):
                    # defaultdict will create a set if one is not present or add to it if one does
                    index[v].add(record[value])
        
            return index
        
        
        restaurant_db = load('/var/tmp/r')
        print(restaurant_db)
        
        by_type = build_index(restaurant_db, 'cuisine', 'name')
        print(by_type)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-08
          • 1970-01-01
          • 2021-05-12
          • 2021-11-17
          • 2019-07-20
          • 1970-01-01
          • 2015-10-29
          • 1970-01-01
          相关资源
          最近更新 更多