【问题标题】:How to sort input without fixed-width field organization?如何在没有固定宽度字段组织的情况下对输入进行排序?
【发布时间】:2019-06-29 01:25:37
【问题描述】:

我有一个 .txt 文件,其中包含以下行:

Name | Email@example.com | Score
Name2 | Email2@madeupsite.com | Score 

其中Score 是一个从 0 到 10 亿的整数。

我想按分数从大到小对这个文件进行排序。我的问题是,由于姓名和电子邮件的长度不同,每次我可以访问它时,分数都不是一致的。我将如何克服这个问题?

(我不太清楚标题的措辞,所以我希望这个机构能更好地解释它;如果问题不清楚,请告诉我)

【问题讨论】:

标签: python csv file-io


【解决方案1】:

#a list to store your data, open the file to retrieve the data
data = []
with open( 'fname.txt' ) as f:
    for line in f:
        # line.split( '|' ) splits the string into a list separated by '|' )
        data.append( line.strip().split('|') )

# convert the scores into an integer
for d in data:
    d[2] = int( d[2] )

# sort the data using 2nd element of row from big to small
sorted_data = sorted( data, key=lambda x: return x[2], reverse=True )

【讨论】:

    【解决方案2】:

    一旦您的行在列表中,您可以使用sortsorted 对其进行排序。诀窍是传递一个提取该整数的键。一种选择是从最后一个| 到行尾取一个切片,并从该字符串中生成一个整数。 rfind() 对此很有帮助:

    lines = ['Name | Email@example.com | 1001',
             'Name2 | Email2@madeupsite.com | 2',
             'Name2 | Email2@madeupsite.com | 200'
    ]
    
    s = sorted(lines, key = lambda s: int(s[s.rfind('|')+1:]))
    list(s)
    

    结果:

    ['Name2 | Email2@madeupsite.com | 2',
     'Name2 | Email2@madeupsite.com | 200',
     'Name | Email@example.com | 1001']
    

    【讨论】:

      【解决方案3】:

      首先,我们可以读取文件的行。接下来,我们使用列表推导在分隔符“|”上拆分每一行,取最后一个索引,并转换为整数进行排序。我们以相反的顺序排序并设置键,因此输出将是行索引,然后将lines_sorted设置为等于已排序行的顺序。

      with open("file.txt", "r") as f:
          lines = f.readlines()
          scores = [int(l.split("|")[-1]) for l in lines]
          sorted_idx = sorted(range(len(scores)), key=lambda k: scores[k], reverse=True)
          lines_sorted = [lines[i] for i in sorted_idx]
      

      有关排序和返回索引的更多建议,请参阅this question

      示例 使用“file.txt”包含以下内容:

      Name | Email@example.com | 1000
      Name2 | Email2@madeupsite.com | 10
      Name3 | Email3@madeupsite.com | 100
      

      lines_sorted 将包含:

      ["Name | Email@example.com | 1000",
       "Name3 | Email3@madeupsite.com | 100", 
       "Name2 | Email2@madeupsite.com | 10"]
      

      【讨论】:

        【解决方案4】:

        对每个字符串的rpartition使用自定义排序键功能

        输入:

        lines = ['Name | Email@example.com | 50',
                 'Name2 | Email2@madeupsite.com | 400',
                 'Name3 | Email2@madeupsite.com | 15']
        

        输出:

        sorted(lines, key=lambda x: int(x.rpartition('|')[-1]))
        
        Out[1128]:
        ['Name3 | Email2@madeupsite.com | 15',
         'Name | Email@example.com | 50',
         'Name2 | Email2@madeupsite.com | 400']
        

        【讨论】:

          【解决方案5】:

          您的输入数据是 PSV(管道分离值)。你可以通过pandas.read_csv with sep='|'阅读:

          dat = """
          Name1 | Email@example.com | 456
          Name2 | Email2@madeupsite.com | 123 
          Name44 | jimmy@yahoo.co.ar | 79
          """
          
          import pandas as pd
          df = pd.read_csv(pd.compat.StringIO(dat), sep='|', header=None)
          
          df.sort_values(2, ascending=True)
          
                   0                        1    2
          2  Name44        jimmy@yahoo.co.ar    79
          1   Name2    Email2@madeupsite.com   123
          0   Name1        Email@example.com   456
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-04-16
            • 1970-01-01
            • 2020-01-25
            • 1970-01-01
            • 1970-01-01
            • 2011-04-12
            • 1970-01-01
            相关资源
            最近更新 更多