【问题标题】:sort array of file's names by value of first row in files按文件中第一行的值对文件名数组进行排序
【发布时间】:2012-06-17 13:08:57
【问题描述】:

我有包含 n 个文件的数组 INPUTFILES

INPUTFILES=( file_0 ... files_n-1 )

我需要按文件中的第一行按数组顺序对它们进行排序。

文件如下所示:

2012.09.20 17:10
2012.11.21 00:10
2012.12.22 15:10
2012.12.23 15:10

我已经有比较两个文件的功能了:

IsSooner () {
ONEFIRST=$( head -1 "${1}" ) 
ONELAST=$( tail -1 "${1}" )
TWOFIRST=$( head -1 "${2}" ) 
TWOLAST=$( tail -1 "${2}" )

TIMEFORMAT='Y.%m.%d %H:%M:'

perl <<EOF
use strict;
use warnings;

use Time::Piece;

open STDERR, "> /dev/null";

my @dates1 = ("${ONEFIRST}","${ONELAST}");
my @range1 = map Time::Piece->strptime("\$_", "${TIMEFORMAT}"), @dates1;

my @dates2 = ("${TWOFIRST}","${TWOLAST}");
my @range2 = map Time::Piece->strptime("\$_", "${TIMEFORMAT}"), @dates2;

if ( \$range1[0] < \$range2[0] ) {
  exit 0;
}

exit 1;
EOF

[ $? -eq 0 ] && {
  return 0
}

return 1  
}

文件中的第一个日期越早,数组中的索引越小。

BASH 中的解决方案(如果需要)。

更新 我事先不知道日期的格式。我只知道它将采用 strftime(3c) 格式。

【问题讨论】:

  • 如果我明白了,你想用 shell 替换 perl 吗?
  • 不。 perl 片段是必需的。我只需要重新排列数组 INPUTFILES 中的顺序。我只是添加了比较功能,因为要设置集合的顺序,您必须有可比较的项目。
  • 为什么需要 perl?它似乎做了比必要的工作更多的工作(为什么要读取每个文件的最后一行?),除了比较两个第一行之外什么都不做。我说,用 user1215106 的回答。
  • @tuxuday 是的,我正在寻找正确的解决方案。第一个想法是使用关联数组,但我不确定。
  • @chepner 这是必要的,因为我没有固定的日期格式(例如是)。并且 bash/nawk 没有 strptime() 等价物。

标签: perl bash sorting


【解决方案1】:
  1. 在简单循环中读取每个文件的第一行并将此信息保存到哈希中,第一行数据为哈希键,文件名为哈希值。

    my @inpufiles = ...;
    my %hash;
    foreach (@inputfiles) {
      open(my $fh, $_) or die $!;
      $hash{<$fh>} = $_;
      close $fh;
    }
    
  2. 按键对哈希进行排序并打印排序后的哈希的所有值。

    foreach (sort (keys(%hash))) {
      print "$hash{$_}\n";
    }
    

    如果你不想打印它,只需将它存储回数组,然后就可以了

    @inputfiles = map {$hash{$_}} sort (keys(%hash));
    

祝你好运!


[更新]

要关注您问题中的更新,我建议您将值存储到散列使用:

$hash{Time::Piece->strptime(<$fh>, $timeformat)->epoch} = $_;

【讨论】:

  • 这是按词法排序的,对。如果是,这对我没有帮助。那是因为我正在使用 Time::Piece 对象来相互比较。
  • @Rob - 其他用户已在您的问题下方发表评论,其中指出 您不需要通过自定义排序对数据进行排序,因为您的数据采用“YYYY.MM.DD HH:NN”格式,并且“词法”排序是这种格式的正确解决方案...
  • 只需将$hash{&lt;$fh&gt;} = $_ 更改为标准化值所需的任何值。我建议标准化为自纪元以来的秒数。
  • 如果第一行相同,此解决方案将删除输入文件。可能是一个真正的问题,因为时间戳通常不是唯一的。
【解决方案2】:

您可以使用Schwartzian Transform 对文件列表进行排序:

my @inputfiles =
  map  { $_->[0] }
  sort { $a->[1] cmp $b->[1] }
  map  { [ $_, do { open my($f), $_; chomp(my $time = <$f>); $time } ] }
    qw/file_0 file_1 file_2/;

这实际上可以写成一个小的 bash 管道,所以你甚至不需要 perl:

INPUTFILES=($(grep -m1 '' file_0 file_1 file_2 | sort -t: -k2 | cut -d: -f1))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-23
    • 2021-08-25
    • 2016-03-01
    • 1970-01-01
    • 2021-04-06
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多