【问题标题】:Grouping elements by two fields on a space delimited file按空格分隔文件上的两个字段对元素进行分组
【发布时间】:2014-10-02 02:31:18
【问题描述】:

我在空格分隔文件中按第 2 列、第 3 列和第 1 列排列了这些数据(我使用 linux 排序来做到这一点):

0 0 2
1 0 2
2 0 2
1 1 4
2 1 4

我想创建一个新文件(保持旧文件不变)

0 2 0,1,2
1 4 1,2

基本上将字段 2 和 3 放在首位,并将字段 1 的元素(作为逗号分隔的列表)按它们分组。有没有办法通过 awk、sed、bash 一个班轮来做到这一点,以避免为此编写 Java、C++ 应用程序?

【问题讨论】:

  • 我不明白/不清楚。我不知道我是否理解第一行“0 2 0,1,2”:{1st row, 2nd col} {1st row, 3rd col} {comma-separated list of values of the 1st column},是正确的方法 ?我不明白“1 4 1,2”是从哪里来的?
  • 输入第 4 行和第 5 行相同。第 2 列和第 3 列,后跟匹配行的第 1 列的值的逗号分隔列表。
  • 我很傻,我没有注意到“x 0 2”出现了 3 次和“x 1 4”出现了两次。我之前的评论对第一行输出错误:逗号分隔的第一列值列表,其中第二和第三值相同(而不是整个第一列的值)。
  • 我对所有正确答案都投了赞成票。

标签: bash awk sed


【解决方案1】:

使用awk

awk '{k=$2 OFS $3} !(k in a){a[k]=$1; b[++n]=k; next} {a[k]=a[k] "," $1}
     END{for (i=1; i<=n; i++) print b[i],a[b[i]]}' file
0 2 0,1,2
1 4 1,2

【讨论】:

  • for (i in a) 不会保持秩序
  • @anubhava。这个答案没有给出正确的输出。也许你可以解决它?
  • @Alexandros:您可以在答案本身中看到生成的输出。但是是的,为了保留它需要一次编辑的顺序。
  • 检查这个输出:0 0 2\n 1 0 2\n 2 0 2\n 1 1 4\n 2 1 4\n 3 1 5\n
【解决方案2】:

由于文件已经排序,您可以在更改时打印该行:

awk '
  seen==$2 FS $3 { line=line "," $1; next }
  { if(seen) print seen, line; seen=$2 FS $3; line=$1 }
  END { print seen, line }
' file
0 2 0,1,2
1 4 1,2

这将保留输出的顺序。

【讨论】:

    【解决方案3】:

    根据您的输入和输出,此行可能会有所帮助:

     awk '{f=$2 FS $3}!(f in a){i[++p]=f;a[f]=$1;next}
          {a[f]=a[f]","$1}END{for(x=1;x<=p;x++)print i[x],a[i[x]]}' file
    

    测试:

    kent$  cat f
    0 0 2
    1 0 2
    2 0 2
    1 1 4
    2 1 4
    
    kent$  awk '{f=$2 FS $3}!(f in a){i[++p]=f;a[f]=$1;next}{a[f]=a[f]","$1}END{for(x=1;x<=p;x++)print i[x],a[i[x]]}' f
    0 2 0,1,2
    1 4 1,2
    

    【讨论】:

      【解决方案4】:
      awk 'a[$2, $3]++ { p = p "," $1; next } p { print p } { p = $2 FS $3 FS $1 } END { if (p) print p }' file
      

      输出:

      0 2 0,1,2
      1 4 1,2
      
      • 该解决方案假定第二列和第三列的数据已排序。

      【讨论】:

        【解决方案5】:

        又一个镜头:

        awk -v SUBSEP=" " '
            {group[$2,$3] = group[$2,$3] $1 ","} 
            END {
                for (g in group) {
                    sub(/,$/,"",group[g])
                    print g, group[g]
                }
            }
        ' file > newfile
        

        SUBSEP 变量是连接一维 awk 数组中字符串的字符。
        http://www.gnu.org/software/gawk/manual/html_node/Multidimensional.html#Multidimensional

        【讨论】:

          【解决方案6】:

          这可能对你有用(GNU sed):

          sed -r ':a;$!N;/(. (. .).*)\n(.) \2.*/s//\1,\3/;ta;s/(.) (.) (.)/\2 \3 \1/;P;D' file
          

          这会将后续记录的第一列附加到第一条记录,直到第二个和第三个键发生变化。然后将第一条记录中的字段重新排列并打印出来。

          这使用提供的数据,但可以适应更复杂的数据。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-01-12
            • 1970-01-01
            • 2013-09-16
            • 2020-09-19
            相关资源
            最近更新 更多