我有一个如下所示的文件:
Time Flag
0.65 5.885581e-01
0.56 5.847484e-01
0.58 5.278409e-01
0.57 1.140746e+00
1.00 0
0.00 0
1.00 1
0.00 0
但这是因为我写的时候忘了转置一些东西。因此,一半的计时最终出现在标志列中,一半的标志最终出现在时间列中。本来应该是
Time Flag
0.65 1
0.59 0
0.56 0
0.58 0
0.58 1
0.53 1
0.57 0
1.14 0
因此,在这个小示例中,前四行应该成为第一列。最后四行应成为第二列。请注意,每列中的一半元素已在原始文件中正确格式化(以交替方式)。重塑和重新格式化它的最简单方法是什么?
答案1
$ awk 'NR > 1 { d[++n] = $1; d[++n] = $2 } END { print "Time", "Flag"; for (i = 1; 2*i <= n; ++i) printf "%.2f%s%d%s", d[i], OFS, d[n/2 + i], ORS }' file
Time Flag
0.65 1
0.59 0
0.56 0
0.58 0
0.58 1
0.53 1
0.57 0
1.14 0
该awk
代码将所有数据按行读取到数组中的连续元素中d
(跳过标头)。
在END
块中,打印标题,然后我们i
从 1 到数组长度的一半进行迭代d
,打印索引处的值i
(时间值)和标记处的值n/2 + i
(标志值)。完成输出的格式化,以便将时间值打印为带有两位小数的浮点值,并将标志值打印为整数。
OFS
和变量ORS
保存默认的输出字段和记录分隔符(默认为空格和换行符)。对于制表符分隔的输出,请使用awk -v OFS='\t' '{ ... }' file
.
作为参考,该awk
代码作为独立脚本:
#!/usr/bin/awk -f
NR > 1 {
d[++n] = $1
d[++n] = $2
}
END {
print "Time", "Flag"
for (i = 1; 2*i <= n; ++i)
printf "%.2f%s%d%s", d[i], OFS, d[n/2 + i], ORS
}
答案2
OP 没有说明问题需要将文件分成两半,修复每一半,然后重新连接在一起,但我想知道在没有这些知识的情况下如何完成它。
我真的很喜欢csvkit尤其是GoCSV用于声明性管道处理。
转换/设置
第一步是将固定宽度示例数据转换为 CSV。 csvkit 让我指定一个列宽模式...
架构.csv
column,start,length
Time,0,4
Flag,7,13
然后转换为 CSV:
in2csv -s schema.csv input.txt > input.csv
分离和转置
我想按类别拆分输入:标志和时间。然后为每个类别制作一组单行 CSV(用于下一步的转置):
gocsv filter -c 2 --regex "^[01]$" input.csv |
gocsv split --max-rows 1 --filename-base flags
对于互补的时间,使用相同的模式--exclude
:
gocsv filter -c 2 --regex "^[01]$" --exclude input.csv |
gocsv split --max-rows 1 --filename-base times
这会生成一组文件,例如:
ls flags-*.csv
flags-1.csv flags-2.csv flags-3.csv flags-4.csv
每个看起来都像:
标志-1.csv
Time,Flag
1.00,0
或者:
times-4.csv
Time,Flag
0.57,1.140746e+00
标Time,Flag
头并不是很重要,但重要的是要看到它的存在并且会影响转置后的结构。
对于每个文件,迭代:转置,选择第二列(因为虚假标题成为第一列),并使用适当的标题进行封顶:
for FILE in flags-*; do
gocsv transpose $FILE |
gocsv select -c 2 |
gocsv cap --names Flag \
> trans_$FILE;
done
for FILE in times-*; do
gocsv transpose $FILE |
gocsv select -c 2 |
gocsv cap --names Time \
> trans_$FILE;
done
堆叠成列
将标志和时间堆叠到各自的列中:
gocsv stack trans_flags* > col_flag.csv
gocsv stack trans_times* > col_time.csv
然后拉链在一起(我只是要使用csvlook因为它有更漂亮的 Markdown 表格,但它也标准化了数字!):
gocsv zip col_time.csv col_flag.csv > output.csv
csvlook output.csv
时间 | 旗帜 |
---|---|
0.650… | 1 |
0.589… | 0 |
0.560… | 0 |
0.585… | 0 |
0.580… | 1 |
0.528… | 1 |
0.570… | 0 |
1.141… | 0 |
这很可爱。
但最后一步是使用 GoCSV 的内置(对我来说是新的)SPRIG 模板和round
清理浮点数、整数和科学记数法的函数。我根据原始列添加新列,然后仅选择新的/格式化的列:
cat output.csv |
gocsv add -n Time -t "{{round .Time 2}}" |
gocsv add -n Flag -t "{{round .Flag 0}}" |
gocsv select -c 3- |
gocsv tsv
我们得到:
Time Flag
0.65 1
0.59 0
0.56 0
0.58 0
0.58 1
0.53 1
0.57 0
1.14 0