【问题标题】:Sort rows in csv file without header & first column对没有标题和第一列的csv文件中的行进行排序
【发布时间】:2018-08-01 21:40:00
【问题描述】:

我有一个包含如下记录的 CSV 文件。

   id,h1,h2,h3,h4,h5,h6,h7 
   101,zebra,1,papa,4,dog,3,apple
   102,2,yahoo,5,kangaroo,7,ape

我想将行排序到这个文件中,没有标题和第一列。我的输出应该是这样的。

  id,h1,h2,h3,h4,h5,h6,h7
  101,1,3,4,apple,dog,papa,zebra
  102,2,5,7,ape,kangaroo,yahoo

我在 AWK 下试过,但不知道如何排除标题和第一列。

awk -F"," ' {
s=""
for(i=1; i<=NF; i++) { a[i]=$i; }
for(i=1; i<=NF; i++)
{
for(j = i+1; j<=NF; j++)
{
if (a[i] >= a[j])
{
temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}
}
for(i=1; i<=NF; i++){ s = s","a[i]; }
print s
} 
' file

谢谢

【问题讨论】:

  • 为什么你的代码没有缩进?

标签: awk sed


【解决方案1】:

如果perl 没问题:

$ perl -F, -lane 'print join ",", $.==1 ? @F : ($F[0], sort @F[1..$#F])' ip.txt
id,h1,h2,h3,h4,h5,h6,h7 
101,1,3,4,apple,dog,papa,zebra
102,2,5,7,ape,kangaroo,yahoo
  • -F, 表示, 作为输入字段分隔符,结果保存在@F 数组中
  • join "," 使用 , 作为输出字段分隔符
  • $.==1 ? @F 第一行,按原样打印
  • ($F[0], sort @F[1..$#F]) 对于其他行,获取第一个字段和其他字段的排序输出
    • .. 是范围运算符,$#F 将给出最后一个字段的索引
    • 您也可以使用(shift @F, sort @F) 代替($F[0], sort @F[1..$#F])

对于给定的标题,排序第一行也可以,所以这可以简化所需的逻辑

$ # can also use: perl -F, -lane 'print join ",", shift @F, sort @F'
$ perl -F, -lane 'print join ",", $F[0], sort @F[1..$#F]' ip.txt
id,h1,h2,h3,h4,h5,h6,h7 
101,1,3,4,apple,dog,papa,zebra
102,2,5,7,ape,kangaroo,yahoo

$ # can also use: ruby -F, -lane 'print [$F.shift, $F.sort] * ","'
$ ruby -F, -lane 'print [$F[0], $F.drop(1).sort] * ","' ip.txt
id,h1,h2,h3,h4,h5,h6,h7 
101,1,3,4,apple,dog,papa,zebra
102,2,5,7,ape,kangaroo,yahoo

【讨论】:

  • perl 摇滚!!你也是!
  • 我刚从your 2nd perl one-liners article 来到这里,说如果您安装了其中一个模块,您可以使用Sort::VersionsSort::Naturally 模块进行自然排序。例如perl -MSort::Naturally -F, -lane 'print join ",", $.==1 ? @F : (shift @F, nsort @F)' ip.txt
  • @cas 谢谢,我最近用过version,也会去看看Sort::Naturally
【解决方案2】:

如果您有gawk,请使用asort

awk -v OFS="," 'NR>1{split($0, a, ",");
                $1=a[1];
                delete a[1];
                n = asort(a, b);
                for (i = 1; i <= n; i++){ $(i+1)=b[i]}};
                1' file.csv

这会将列拆分为数组a,分隔符为,,用于除第一个以外的所有原始数据。

然后将原始列中的第一个值与a 中的第一个值一起分配,并从a 中删除该值。

现在a 被排序为b 并从2 列开始赋值。然后打印它。

【讨论】:

    【解决方案3】:

    您可以根据您的要求使用awk 中的asort() 函数,然后从第二行开始对它们进行排序。解决方案是 GNU awk 特定的,因为 length(array) 函数

    awk 'NR==1{ print; next }
         NR>1 { finalStr="" 
                arrayLength=""
                delete b
                split( $0, a, "," )
                for( i = 2; i <= length(a); i++ )
                    b[arrayLength++] = a[i]
                asort( b )
                for( i = 1; i <= arrayLength ; i++ ) 
                    finalStr = (finalStr)?(finalStr","b[i]):(b[i])
                printf( "%s", a[1]","finalStr )
                printf( "\n" ); 
        }' file
    

    我们的想法是,首先我们用, 分隔符将整行拆分为数组a,从中我们将第二个字段中的元素从新数组b 中取出。我们对这个新数组中的这些元素进行排序,并在最终打印时附加第一个列元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-02
      • 2019-01-19
      • 1970-01-01
      • 2014-07-26
      • 2018-05-24
      • 2016-03-16
      • 2017-12-28
      • 2014-10-26
      相关资源
      最近更新 更多