【问题标题】:Sort A list of Strings Based on certain field根据特定字段对字符串列表进行排序
【发布时间】:2016-11-18 05:34:43
【问题描述】:

概述:我有类似这样的数据(每一行都是一个字符串):

81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22 :22:22:22:23,空,^M 3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33: 33:33:31,空,^M B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33: 33:33:32,空,^M 61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33: 33:33:33,空,^M

我想根据每个字符串中存在的第一个时间戳对每一行进行排序,这四个记录是:

2016-07-14 01:28:59

2016-07-14 06:25:32

2016-07-14 08:26:45

2016-07-14 14:29:13

现在我知道sort() 方法,但我不明白如何使用此处根据此(时间戳)数量对所有行进行排序,并且我确实需要保持最终排序数据的格式与其他一些服务将使用它。

我也知道我可以制作key(),但我不清楚如何对时间戳字段进行排序。

【问题讨论】:

  • 格式总是一样的吗?你知道第一个时间戳总是第二个(在第一个逗号之后)吗?
  • 是的,总是一样的。

标签: python list python-2.7 sorting


【解决方案1】:

您可以使用列表方法list.sort 进行就地排序或使用sorted() 内置函数返回一个新列表。 key 参数采用一个函数,该函数在排序之前应用于序列的每个元素。您可以结合使用string.split(',') 和对第二个元素的索引,例如some_list[1],所以:

In [8]: list_of_strings
Out[8]: 
['81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22:22:22:22:23,null,^M',
 '3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33:33:33:31,null,^M',
 'B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33:33:33:32,null,^M',
 '61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33:33:33:33,null,^M']

In [9]: sorted(list_of_strings, key=lambda s: s.split(',')[1])
Out[9]: 
['3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33:33:33:31,null,^M',
 '61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33:33:33:33,null,^M',
 'B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33:33:33:32,null,^M',
 '81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22:22:22:22:23,null,^M']

或者,如果您希望对列表进行适当的排序,

list_of_strings
Out[12]: 
['81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22:22:22:22:23,null,^M',
 '3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33:33:33:31,null,^M',
 'B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33:33:33:32,null,^M',
 '61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33:33:33:33,null,^M']

list_of_strings.sort(key=lambda s: s.split(',')[1])

list_of_strings
Out[14]: 
['3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33:33:33:31,null,^M',
 '61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33:33:33:33,null,^M',
 'B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33:33:33:32,null,^M',
 '81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22:22:22:22:23,null,^M']

【讨论】:

    【解决方案2】:

    如果不改变行本身的格式,也许(我不知道解决方案的更广泛背景)一个简单的 shell 转换很合适(我知道它不是 python 解决方案)。

    所以:

    $ sort -t, -k2,2 sort_me_on_first_timestamp_field.txt 
    3B:3F:B9:0A:83:E6, 2016-07-14 01:28:59, 2016-07-14 01:29:01, -36, 33:33:33:33:33:31,null,^M 
    61:01:55:16:B5:52, 2016-07-14 06:25:32, 2016-07-14 06:25:34, -56, 33:33:33:33:33:33,null,^M
    B3:C0:6E:77:E5:31, 2016-07-14 08:26:45, 2016-07-14 08:26:47, -65, 33:33:33:33:33:32,null,^M 
    81:0A:D7:19:25:7B, 2016-07-14 14:29:13, 2016-07-14 14:29:15, -69, 22:22:22:22:22:23,null,^M 
    

    在我看来还不错。 -t 选项告诉 sort 使用逗号作为分隔符, -k2,2 请求根据第二个“字段”进行排序(它从一开始计数)。有时使用 -n 切换到数字排序很重要,但在这里使用固定长度的 ISO 日期时间字符串,它应该适用于词法排序。

    再次:如果您正在寻找纯 python 解决方案,我建议选择建议的基于 python 的答案。这在这里只是建议一个基线替代方案。

    更新以“测量”某些机器上的某些场景 - 好吧:

    在“开发者的机器”上,将 4 行多次连接的样本排序为 20、200、2000、...、2,000,000 行的文件需要 12 毫秒到 1.7 秒(对于 200 万行)使用 sort 命令写入 /dev/null 和 2 秒写入文件进行排序。

    @juanpa.arrivillaga 提出的就地路线排序的简单实现:

    #! /usr/bin/env python
    FILE_PATH_IN = './fhf.txt'
    NL, FS = '\n', ','
    
    list_of_strings = open(FILE_PATH_IN).read().split(NL)[:-1]
    list_of_strings.sort(key=lambda s: s.split(FS)[1])
    with open(FILE_PATH_IN + ".out", "wt") as f:
        f.write(NL.join(list_of_strings))
    

    在同一台机器上大约需要。对于 200 万行的情况,其他变体(使用 sorted 生成新列表)需要 3 秒:

    #! /usr/bin/env python
    FILE_PATH_IN = './fhf.txt'
    NL, FS = '\n', ','
    
    list_of_strings = open(FILE_PATH_IN).read().split(NL)[:-1]
    with open(FILE_PATH_IN + ".out", "wt") as f:
        f.write(NL.join(sorted(list_of_strings, key=lambda s: s.split(',')[1])))
    

    所以建议是,使用纯python解决方案。

    【讨论】:

    • 因此,既然 shell 和 python 都可以用来完成任务,那么我就想到了下一个问题:如果我有一个包含 20,00,000 条记录的文件,哪种方法更好: 1. 阅读python程序中的文件->将所有记录放入列表中->对列表进行排序->将排序后的列表放入新文件或使用shell对文件进行排序?请建议
    • 如今,200 万行在内存中并不多,因此这两种方式对于大多数用途来说都足够了。当罕见的缺陷潜入数据(截断行等)时,python 解决方案可能会提供更好的工具集来清理传入的数据,并且如果读取器和写入器不放慢速度,那将是一件好事。但是你总是可以测量(因为 shell 命令就在那里),并以此为基础做出决定。请注意,python 提出的解决方案已经就位,因此您也不会使用它生成多个副本。
    • 是的,如果我使用 shell,它将写入一个新文件。感谢您的洞察力。
    • 在 shell 术语中,所有的“管道”都是开放的,比如cat fhf.txt | sort -t, -k2,2 > out_file.txt,而不是cat fhf.txt 部分,一些源进程可能会直接将传入的数据写入管道,排序从中读取,然后要么通过管道进入排序数据的后续消费者,要么像这里一样写入输出文件。
    • (Y) 用于时间计算洞察
    【解决方案3】:

    你可以使用string.split(),string.split(',')[1]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      • 2023-01-21
      • 2018-02-23
      • 2011-04-03
      • 1970-01-01
      • 2019-07-13
      • 1970-01-01
      相关资源
      最近更新 更多