Linux 如何消除文件中int值之间的间隙?
给定一个包含两列整数的文件,我想消除整数值之间的间隙。我的意思是,如果我们取两个整数A和B,在某种程度上没有C,比如ALinux 如何消除文件中int值之间的间隙?,linux,bash,shell,awk,command-line,Linux,Bash,Shell,Awk,Command Line,给定一个包含两列整数的文件,我想消除整数值之间的间隙。我的意思是,如果我们取两个整数A和B,在某种程度上没有C,比如A 1 2 1 3 2 5 6 9 3 5 7 9 11 6 7 11 为此: 1 2 1 3 2 4 5 7 3 4 6 7 8 5 6 8 在前两列中,当前整数为{1,2,3,5,6,7,9,11}。缺少的值是{4,8,10}。目标是将每个整数减少小于它的缺失值的数量。 因此,5、6和7减少了1,9 us减少了2,11 us减少了3。 所以值{1,2,3,5,6,7,9,
1 2
1 3
2 5
6 9
3 5
7 9
11 6
7 11
为此:
1 2
1 3
2 4
5 7
3 4
6 7
8 5
6 8
在前两列中,当前整数为{1,2,3,5,6,7,9,11}。缺少的值是{4,8,10}。目标是将每个整数减少小于它的缺失值的数量。
因此,5、6和7减少了1,9 us减少了2,11 us减少了3。
所以值{1,2,3,5,6,7,9,11}被{1,2,3,4,5,6,7,8}替换。
有人知道如何使用linux命令、bash脚本或awk命令高效地完成这项工作吗?
谢谢大家!
编辑:
我试着去做,但是我没有找到一种在shell脚本中实现的方法,我必须编写一个执行shell脚本的c程序。
第一部分只是对文件进行排序,第二部分是我在问题中提到的
#包括
#包括
#包括
#包括
#定义最大整数100000000
无效进程_文件(字符*路径){
//第一部分
char*outpath=“tmpfile”;
char*command=calloc(456+3*strlen(path)+strlen(outpath),sizeof(char));
sprintf(command,“#!/bin/bash\nvar1=$(cat%s | head-n4&&(cat%s | tail-n+5 | awk'{split($0,a,\“\”);asort(a);for(i=1;i这可以做到:
awk '(NR==FNR){for(i=1;i<=NF;++i) {a[$i]; max=(max<$i?$i:max)};next}
(FNR==1) {for(i=1;i<=max;++i) if(i in a) a[i]=++c }
{for(i=1;i<=NF;++i) $i=a[$i]}1' file file
上述命令将返回:
1 2
1 3
2 4
5 7
3 4
6 7
8 5
6 8
此方法的思想是跟踪数组a
,该数组由旧值索引并返回新值:a[old]=new
。我们扫描文件两次,并将所有可能的值存储在a[old]中
。当我们第二次读取文件时,我们首先检查新值将是什么。完成后,我们只需用新值更新所有字段并打印结果
也可以通过一次性读取文件来完成上述操作,只需缓冲一点:
awk '{b[FNR]=$0;for(i=1;i<=NF;++i) {a[$i]; max=(max<$i?$i:max)}}
END {
for(i=1;i<=max;++i) if(i in a) a[i]=++c
for(n=1;n<=FNR;++n) {
$0=b[n]
for(i=1;i<=NF;++i) $i=a[$i]
print
}
}' file
awk'{b[FNR]=$0;for(i=1;i假设您的输入如下所示:
input.txt
2 1
4 3
5 5
6 2
1 4
8 7
9 6
7 9
注意:col1中没有3,col2中没有8,只是为了便于跟踪
然后分别对每列进行排序并存储:
$sort -k1,1 input.txt | awk '{ print $1}' > 1_sorted
$cat 1_sorted
1
2
4
5
6
7
8
9
$sort -k2,2 input.txt | awk '{ print $2}' > 2_sorted
$cat 2_sorted
1
2
3
4
5
6
7
9
现在只需合并两个文件:
$paste -d' ' 1_sorted 2_sorted > merged_again
$ cat merged_again
1 1
2 2
4 3
5 4
6 5
7 6
8 7
9 9
可能有一种性能更高/更优雅的方法,但我现在想不起来。使用GNU awk和asorti()
:
@我明白了,但问题是,在我看来,这似乎是一件简单的事情,我似乎没有找到一种有效的方法,我补充了我试图做的do@Inian我添加了我尝试过的内容,但它不起作用的原因是执行时间太长,因为我使用sed将每一行替换为新值,时间复杂度为n^2,我我在寻找一种更有效的方法。我想我的大问题是-为什么?你想创建一个特定的输出吗?然后忽略这个,只写那个输出。如果你特别想做的是根据规则编辑这个文件,那么我不清楚规则。下面的答案中有一些好的想法。这是你选择的在这组复杂的c
代码中调用sed
表示您不熟悉awk
。它使像您这样的任务能够在一个进程中处理所有任务,并将显著减少您的运行时间。有了JohnBrown的解决方案,您甚至可以使用内置功能来减少代码库。不确定您的ata可以工作,但希望您知道*nix utitiltytsort
(地形排序)。它可能是您工具箱的另一个好工具。祝您好运!哦,还有++通过显示代码来改进您的Q。祝您好运。不是我,但我只是尝试了一下,它没有提供所需的输出:您的文件看起来像什么?(关于我的输入,请参见我的答案)我想你没有理解我的问题,请看一下我的例子和我的程序。值的位置不重要,重要的是如果我们取任意两个不同的整数a和B,其中a>B,并且文件中没有整数C,比如CB,那么a-B=1。为此,我列出了最小和最大值之间的所有整数文件中的st integer,我指的是不存在于文件中。然后,对于文件中的每个整数,我将其值减少为小于它的缺失整数的数量。很明显,我认为@kvantour是您想要的解决方案
$paste -d' ' 1_sorted 2_sorted > merged_again
$ cat merged_again
1 1
2 2
4 3
5 4
6 5
7 6
8 7
9 9
$ gawk '{ # GNU awk only or implement sort
a[$1];a[$2] # hash field values to a array
f1[NR]=$1;f2[NR]=$2 # hash fields $1 and $2 index on NR
}
END { # after all data is hashed
asorti(a,a,"@ind_num_asc") # sort index of a where the values are
for(i in a) # make a reverse map
b[a[i]]=i
for(i=1;i<=NR;i++) # iterate the stored "records"
print b[f1[i]],b[f2[i]] # print and fetch from reverse map
}' file
1 2
1 3
2 4
5 7
3 4
6 7
8 5
6 8