【问题标题】:Group and Check-mark using Python使用 Python 进行分组和复选标记
【发布时间】:2011-09-05 01:18:34
【问题描述】:

我有几个文件,每个文件都有这样的数据(文件名:里面的数据由换行符分隔):

  1. 迈克:飞机\n汽车
  2. Paula:飞机\n火车\n船\n汽车
  3. 比尔:船\n火车
  4. 斯科特:汽车

如何使用 python 创建一个 csv 文件,将所有不同的车辆分组,然后将 X 放在适用的人身上,例如:

【问题讨论】:

  • 行号是否也在你的文件中?
  • 不,那只是为了表明有单独的文件。

标签: python csv


【解决方案1】:

以下是如何解析此类文件的示例。

注意这里的字典是无序的。您可以使用标准库中的有序字典(在 Python 3.2 / 2.7 的情况下),如果您有较旧的 Python 版本或只是将订单保存在附加列表中,请查找任何可用的实现/反向移植 :)

data = {}
name = None

with open(file_path) as f:
    for line in f:
        if ':' in line: # we have a name here
            name, first_vehicle = line.split(':')
            data[name] = set([first_vehicle, ])  # a set of vehicles per name
        else:
            if name:
                data[name].add(line)

# now a dictionary with names/vehicles is available
# let's convert it to simple csv-formatted string..

# a set of all available vehicles
vehicles = set(v for vlist in data.values()
               for v in vlist)

for name in data:
    name_vehicles = data[name]
    csv_vehicles = ''
    for v in vehicles:
        if v in name_vehicles:
            csv_vehicles += v
        csv_vehicles += ','

    csv_line = name + ',' + csv_vehicles

【讨论】:

    【解决方案2】:

    假设输入如下所示:

    Mike: Plane
    Car
    Paula: Plane
    Train
    Boat
    Car
    Bill: Boat
    Train
    Scott: Car
    

    这个 python 脚本将车辆放在字典中,由人索引:

    #!/usr/bin/python
    
    persons={}
    vehicles=set()
    
    with open('input') as fd:
        for line in fd:
            line = line.strip()
            if ':' in line:
                tmp = line.split(':')
                p = tmp[0].strip()
                v = tmp[1].strip()
                persons[p]=[v]
                vehicles.add(v)
            else:
                persons[p].append(line)
                vehicles.add(line)
    
    for k,v in persons.iteritems():
        print k,v
    
    print 'vehicles', vehicles
    

    结果:

    Mike ['Plane', 'Car']
    Bill ['Boat', 'Train']
    Scott ['Car']
    Paula ['Plane', 'Train', 'Boat', 'Car']
    vehicles set(['Train', 'Car', 'Plane', 'Boat'])
    

    现在,所有需要的数据都放在数据结构中。 csv 部分留给读者作为练习:-)

    【讨论】:

      【解决方案3】:

      假设这些行号不存在(如果存在则很容易修复),并且输入文件如下:

      Mike: Plane
      Car
      Paula: Plane
      Train
      Boat
      Car
      Bill: Boat
      Train
      Scott: Car
      

      可以在这里找到解决方案:https://gist.github.com/999481

      import sys
      from collections import defaultdict
      import csv
      
      # see http://stackoverflow.com/questions/6180609/group-and-check-mark-using-python
      def main():
          # files = ["group.txt"]
          files = sys.argv[1:]
          if len(files) < 1:
              print "usage: ./python_checkmark.py file1 [file2 ... filen]"
      
          name_map = defaultdict(set)
      
          for f in files:
              file_handle = open(f, "r")
              process_file(file_handle, name_map)
              file_handle.close()
      
          print_csv(sys.stdout, name_map) 
      
      def process_file(input_file, name_map):
          cur_name = ""
          for line in input_file:
              if ":" in line:
                  cur_name, item = [x.strip() for x in line.split(":")]
              else:
                  item = line.strip()
              name_map[cur_name].add(item)
      
      
      def print_csv(output_file, name_map):
          names = name_map.keys()
          items = set([])
          for item_set in name_map.values():
              items = items.union(item_set)
      
          writer = csv.writer(output_file, quoting=csv.QUOTE_MINIMAL)
          writer.writerow( [""] + names )
          for item in sorted(items):
              row_contents = map(lambda name:"X" if item in name_map[name] else "", names)
              row = [item] + row_contents
              writer.writerow( row )
      
      
      if __name__ == '__main__':
          main()
      

      输出:

      ,Mike,Bill,Scott,Paula 
      Boat,,X,,X 
      Car,X,,X,X 
      Plane,X,,,X 
      Train,,X,,X 
      

      这个脚本唯一不做的就是按照名称所在的顺序保留列。可以保留一个单独的列表来维护顺序,因为地图/字典本质上是无序的。

      【讨论】:

      • 这个很好用,唯一的问题是文件输出在每一行之后生成一个换行符。
      • 嗯..你不希望每一行都在自己的行上吗?
      • 其实问题是我没有按照post这个post
      • 啊,我明白了。很高兴知道 - 考虑到它是文本,以二进制模式打开文件非常不直观。
      【解决方案4】:

      最优雅和最简单的方法是这样的:

      vehiclesToPeople = {}
      people = []
      
      for root,dirs,files in os.walk('/path/to/folder/with/files'):
          for file in files:
              person = file
              people += [person]
              path = os.path.join(root, file)
      
              with open(path) as f:
                  for vehicle in f:
                      vehiclesToPeople.setdefault(vehicle,set()).add(person)
      
      people.sort()
      table = [ ['']+people ]
      for vehicle,owners in peopleToVehicles.items():
          table.append([('X' if p in vehiclesToPeople[vehicle] else '') for p in people])
      
      csv = '\n'.join(','.join(row) for row in table)
      

      你也可以pprint.pprint(table)看看。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多