我有一个文件,其中包含按时间戳排序的条目,但其中包含同一时间戳的多个实例,每个实例都有一个单独的主题。我想将具有相同时间戳的所有条目连接到一行。时间戳是第1列
输入文件可能会读取
Time,Tag,Value
1,ABC,3
2,ABC,2.7
2,DEF,3.4
3,ABC,2.8
3,DEF,3.6
3,GHI,2.99
3,JKL,3.01
4,ABC,3.42
4,DEF,3.62
4,JKL,3.82
期望的输出就像(选项1);
Time,Tag,Value
1,ABC,3
2,ABC,2.7,DEF,3.4
3,ABC,2.8,DEF,3.6,GHI,2.99,JKL,3.01
4,ABC,3.42,DEF,3.62,JKL,3.82
更好的是(选项2);
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
我认为我可以通过使用循环编写脚本来获得选项1。首先要求我获取“Tag”的所有值的唯一列表,以确定需要循环的迭代次数。
但我也在假设;
1)即使在bash中,这对于长文件来说也是昂贵的;和 2)可能有一些更优雅的方式。
Newb问题。所有帮助表示赞赏
由于
答案 0 :(得分:1)
这样可行:
awk -F, '{if($1 in a){ split(a[$1],t,","); a[$1]=t[1]"|"$2","t[2]"|"$3
}else a[$1]=$2","$3;}END{asort(a);for(x in a)print x","a[x]}' file|sort -n
以你的例子:
kent$ awk -F, '{if($1 in a){split(a[$1],t,","); a[$1]=t[1]"|"$2","t[2]"|"$3
}else a[$1]=$2","$3;}END{asort(a);for(x in a)print x","a[x]}' file|sort -n
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
答案 1 :(得分:1)
新答案:
我意识到我以前的答案可能难以阅读和理解 - 特别是对于初学者。然而,它确实充分利用了gawk的数组排序功能,这对于处理您在问题中谈到的“标记”的唯一值非常有用。但是,在阅读了一些评论之后,我相信我可能误解了你的问题 - 也许只是略有不同。这是一种不关心“标签”及其值的唯一性的方法。它只是加入了他们。它也应该是非常易读和可扩展的。像:
一样运行awk -f script.awk file
script.awk的内容:
BEGIN {
FS=OFS=","
}
NR==1 {
print
next
}
{
tag[$1]=(tag[$1] ? tag[$1] "|" : "") $2
val[$1]=(val[$1] ? val[$1] "|" : "") $3
}
END {
for (i in tag) {
print i, tag[i], val[i] | "sort -n"
}
}
结果:
Time,Tag,Value
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
或者,这是单行:
awk -F, 'NR==1 { print; next } { tag[$1]=(tag[$1] ? tag[$1] "|" : "") $2; val[$1]=(val[$1] ? val[$1] "|" : "") $3 } END { for (i in tag) print i, tag[i], val[i] | "sort -n" }' OFS=, file
以前的答案:
这是使用GNU awk
的一种方式。像:
awk -f script.awk file
script.awk
的内容:
BEGIN {
FS=OFS=","
}
NR==1 {
print
next
}
{
a[$1][$2]=$3
}
END {
for (i in a) {
b[x++] = i
}
n = asort(b)
for (j=1;j<=n;j++) {
m = asorti(a[b[j]],c)
for (k=1;k<=m;k++) {
s = (s ? s "|" : "") c[k]
r = (r ? r "|" : "") a[b[j]][c[k]]
}
print b[j], s, r
s = r = ""
}
}
结果:
Time,Tag,Value
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
或者,这是单行:
awk -F, 'NR==1 { print; next } { a[$1][$2]=$3 } END { for (i in a) b[x++] = i; n = asort(b); for (j=1;j<=n;j++) { m = asorti(a[b[j]],c); for (k=1;k<=m;k++) { s = (s ? s "|" : "") c[k]; r = (r ? r "|" : "") a[b[j]][c[k]] } print b[j], s, r; s = r = "" } }' OFS=, file
答案 2 :(得分:1)
假设您的数据按时间顺序排列,您可以使用此awk解决方案:
parse.awk
# Use comma as input and output field separators
BEGIN { FS = OFS = "," }
# Print header and skip to next line
NR == 1 { print; next }
# If previous timestamp is the same as current append tag and value
pt == $1 {
tag = tag "|" $2
val = val "|" $3
}
# If not the first data line and timestamps are not equal then print
NR != 2 && pt != $1 { print pt, tag, val }
# Save previous timestamp and reset accumulator variables
pt != $1 {
pt = $1
tag = $2
val = $3
}
END { print pt, tag, val }
像这样运行:
awk -f parse.awk infile
输出:
Time,Tag,Value
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
或者作为一个单行:
<infile awk 'BEGIN {FS=OFS=","} NR==1{print;next} pt==$1 {tag=tag"|"$2;val=val"|"$3} NR!=2&&pt!=$1 {print pt,tag,val} pt!=$1 {pt=$1;tag=$2;val=$3} END {print pt,tag,val}'
答案 3 :(得分:0)
bash
可能是错误的工具。试试Python:
import fileinput
import sys
oldTime = None
for line in fileinput.input():
line = line.strip()
pos = line.find(',')
time = line[0:pos]
if oldTime == time:
sys.stdout.write(',')
sys.stdout.write(line[pos+1:])
else:
if oldTime is not None:
sys.stdout.write('\n')
sys.stdout.write(line)
oldTime = time
sys.stdout.write('\n')
答案 4 :(得分:0)
如果这是您想要经常重复的操作,我会选择使用更多'完整'脚本语言编写的实用程序脚本。然后,您可以在自己的bash脚本中调用脚本,或者在需要时在命令行中使用它。
这是一个Python示例:
#!/usr/bin/env python
# --- merge_groups.py ----
import fileinput, operator, itertools
lines = (line.strip() for line in fileinput.input())
data = (line.split(",") for line in lines if line)
for key, group in itertools.groupby(data, operator.itemgetter(0)):
_, label, value = zip(*group)
print "%s,%s,%s" % (key, "|".join(label), "|".join(value))
请注意,该脚本假定具有相同时间戳的条目已经组合在一起。
您可以使用该脚本直接处理现有数据文件或管道数据,例如:
[me@home]$ ./merge_groups.py data.txt # parse existing data file
Time,Tag,Value
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
[me@home]$ cat data.txt | ./merge_groups.py # post-process command output
Time,Tag,Value
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
答案 5 :(得分:0)
答案 6 :(得分:0)
以防万一你需要一个awk解决方案!
function read() {
split($0, buf, ",")
}
function write() {
for (i = 1; i < length(buf); i++) {
printf "%s,", buf[i]
}
print buf[length(buf)]
}
BEGIN {
FS = ","
}
NR == 1 {
print
next
}
NR == 2 {
read()
next
}
{
if ($1 != time) { # new time
time = $1
write()
read()
} else { # repeated time
for (i = 2; i <= NF; i++) {
buf[i] = buf[i] "|" $i
}
}
}
END {
write()
}
我对awk不太好,所以我必须强调可读性!
答案 7 :(得分:0)
嗯,您确实说过“所有帮助”,那么包含Ruby解决方案会是什么?
require 'csv'
puts(CSV.read('f.csv').group_by(&:first).map do |k, v|
t = v.transpose
[k, t[1].join('|'), t[2].join('|')].join(',')
end.drop(1))
答案 8 :(得分:0)
Perl没有代表。
use strict;
my $skip_header = <>;
my %d;
while(<>) {
s/\s+$//;
my ($no, $k, $v ) = split ",";
push @{$d{int($no)}}, [ $k, $v ];
}
END {
foreach my $no (sort { $a <=> $b } keys %d ) {
print $no, ",";
print join("|", map { $_->[0] } @{$d{$no}});
print ",";
print join("|", map { $_->[1] } @{$d{$no}});
print "\n";
}
}
给出:
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
答案 9 :(得分:0)
对于第一个选项,您可以尝试:
awk -F, 'p x!=$1{if(p x)print s; p=s=$1} {sub($1,x); s=s $0} END{print s}' file
答案 10 :(得分:0)
第一个:
> awk -F, '{a[$1]=a[$1]","$2","$3}END{for(i in a)print i","substr(a[i],2)}' temp | sort
1,ABC,3
2,ABC,2.7,DEF,3.4
3,ABC,2.8,DEF,3.6,GHI,2.99,JKL,3.01
4,ABC,3.42,DEF,3.62,JKL,3.82
第二个:
> awk -F, '{a[$1]=a[$1]"|"$2;b[$1]=b[$1]"|"$3}END{for(i in a)print i","substr(a[i],2)","substr(b[i],2)}' temp | sort
1,ABC,3
2,ABC|DEF,2.7|3.4
3,ABC|DEF|GHI|JKL,2.8|3.6|2.99|3.01
4,ABC|DEF|JKL,3.42|3.62|3.82
答案 11 :(得分:0)
sed
方式sed -ne ':a;$!N;/^\([0-9]\+\),.*\n\1,/s/\n[0-9]*//;ta;P;D'
Time,Tag,Value
1,ABC,3
2,ABC,2.7,DEF,3.4
3,ABC,2.8,DEF,3.6,GHI,2.99,JKL,3.01
4,ABC,3.42,DEF,3.62,JKL,3.82