在CSV文件中查找模式

时间:2019-01-10 09:37:17

标签: csv awk

尝试根据重复的行对csv文件进行排序

awk -F, 'NR>1{arr[$4,",",$5,",",$6,,",",$7,",",$8,",",$9]++}END{for (a in arr) printf "%s\n",  arr[a] "-->" a}' test.txt

输入文件

a,b,d,1,2,3,4,5,6,y,x,z
k,s,t,1,2,3,4,5,6,t,z,s
a,b,k,1,4,5,5,5,6,k,r,s

使用以下文件创建文件

a,b,d,1,2,3,4,5,6,y,x,z-->2
k,s,t,1,2,3,4,5,6,2,t,z,s-->2
a,b,k,1,4,5,5,5,6,1,k,r,s-->1
  • 最后一列包含从第4位到第9位的数字模式的出现次数。

对重复的行进行计数和排序

我直言我有带计数的模式-但我不知道如何将其余的列添加到该行:

感谢您的支持。

5 个答案:

答案 0 :(得分:0)

一种解决方案,其中数据被读取两次,第一次是对重复项进行计数,第二次是输出:

$ awk -F, '
NR==FNR {
    a[$4 ORS $5 ORS $6 ORS $7 ORS $8 ORS $9]++              # count
    next
}
{
    print $0 "-->" a[$4 ORS $5 ORS $6 ORS $7 ORS $8 ORS $9] # output
}' file file
a,b,d,1,2,3,4,5,6,y,x,z-->2
k,s,t,1,2,3,4,5,6,t,z,s-->2
a,b,k,1,4,5,5,5,6,k,r,s-->1

答案 1 :(得分:0)

您也可以尝试Perl。该文件只能读取一次,因此会更快。检查一下:

$ cat shimon.txt
a,b,d,1,2,3,4,5,6,y,x,z
k,s,t,1,2,3,4,5,6,t,z,s
a,b,k,1,4,5,5,5,6,k,r,s
$ perl -F, -lane ' $v=join(",",@F[3..8]);$kv{$_}{$v}=$kv2{$v}++; END { while(($x,$y)=each (%kv)){ while(($p,$q)=each (%{$y})) { print "$x --> $kv2{$p}" }}}' shimon.txt
a,b,k,1,4,5,5,5,6,k,r,s --> 1
a,b,d,1,2,3,4,5,6,y,x,z --> 2
k,s,t,1,2,3,4,5,6,t,z,s --> 2
$

另一个Perl-较短的代码

$ perl -F, -lane ' $kv{$_}=$kv2{join(",",@F[3..8])}++; END { for(keys %kv) { $t=join(",",(split /,/)[3..8]); print "$_ --> $kv2{$t}" } } ' shimon.txt
a,b,k,1,4,5,5,5,6,k,r,s --> 1
a,b,d,1,2,3,4,5,6,y,x,z --> 2
k,s,t,1,2,3,4,5,6,t,z,s --> 2

$ perl -F, -lane ' $kv{$_}=$kv2{join(",",@F[3..8])}++; END { for(keys %kv) { print "$_ --> ",$kv2{join(",",(split /,/)[3..8])} } } ' shimon.txt
a,b,k,1,4,5,5,5,6,k,r,s --> 1
a,b,d,1,2,3,4,5,6,y,x,z --> 2
k,s,t,1,2,3,4,5,6,t,z,s --> 2
$

答案 2 :(得分:0)

能否请您尝试以下操作,仅读取一次Input_file。

awk '
BEGIN{
  FS=OFS=","
}
{
  a[FNR]=$0
  b[FNR]=$4 FS $5 FS $6 FS $7 FS $8 FS $9
  c[$4 FS $5 FS $6 FS $7 FS $8 FS $9]++
}
END{
  for(i=1;i<=FNR;i++){
    print a[i]" ---->" c[b[i]]
  }
}'  Input_file

答案 3 :(得分:0)

James Brown的答案是一个非常简单的两次通过解决方案,它的优点是您不需要将文件存储到内存中,但缺点是必须读取两次文件。以下解决方案将进行相反的处理,仅读取文件,但必须将其保存到内存中。为此,我们需要3个数组。数组c用来跟踪计数,数组b用作缓冲区,数组a用来跟踪原始顺序。

此外,我们将利用多维数组索引:

  

有效的数组索引应包含一个或多个<逗号>分隔的表达式,类似于在某些编程语言中对多维数组进行索引的方式。因为awk数组实际上是一维的,所以这样一个用<逗号>分隔的列表应通过串联各个表达式的字符串值而转换为单个字符串,每个表达式之间都用SUBSEP变量的值分隔开。因此,以下两个索引操作应等效:

var[expr1, expr2, ... exprn]
var[expr1 SUBSEP expr2 SUBSEP... SUBSEP exprn]

解决方案现在显示为:

{ a[NR] = $4 SUBSEP $5 SUBSEP $6 SUBSEP $7 SUBSEP $8 SUBSEP $9
  b[$4,$5,$6,$7,$8,$9] = $0
  c[$4,$5,$6,$7,$8,$9]++ }
END { for(i=1;i<=NR;++i) print b[a[i]],"-->",c[a[i]] }

答案 4 :(得分:0)

由于问题类似于SQL模式,因此也可以使用sqlite。检查一下。

$ cat shimon.txt
a,b,d,1,2,3,4,5,6,y,x,z
k,s,t,1,2,3,4,5,6,t,z,s
a,b,k,1,4,5,5,5,6,k,r,s
$ cat sqllite_cols4_to_9.sh
#!/bin/sh
sqlite3 <<EOF
create table data(c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12);
.separator ','
.import "$1" data
select t1.*, " --> " || t2.cw from data t1, ( select c4,c5,c6,c7,c8,c9, count(*) as cw from data group by c4,c5,c6,c7,c8,c9 ) t2
where t1.c4=t2.c4 and t1.c5=t2.c5 and t1.c6=t2.c6 and t1.c7=t2.c7 and t1.c8=t2.c8 and t1.c9=t2.c9;
EOF
$ ./sqllite_cols4_to_9.sh shimon.txt
a,b,d,1,2,3,4,5,6,y,x,z, --> 2
k,s,t,1,2,3,4,5,6,t,z,s, --> 2
a,b,k,1,4,5,5,5,6,k,r,s, --> 1
$