【发布时间】:2020-06-12 15:26:15
【问题描述】:
给定一个包含两列整数的文件,我想消除整数值之间的间隙。所谓间隙,我的意思是如果我们取两个整数 A 和 B,那么就没有像 A 这样的 C
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 减少了 3。 所以值 {1,2,3,5,6,7,9,11} 被 {1,2,3,4,5,6,7,8} 替换。 有谁知道如何有效地做到这一点,使用 linux 命令、bash 脚本或 awk 命令? 谢谢!
编辑: 我尝试这样做,但我没有找到在 shell 脚本中执行此操作的方法,我不得不编写一个执行 shell 脚本的 c 程序。 第一部分只是对文件进行排序,第二部分执行我在问题中谈到的内容。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_INTS 100000000
void process_file(char *path){
//FIRST PART
char *outfpath="tmpfile";
char *command=calloc(456+3*strlen(path)+strlen(outfpath),sizeof(char));
sprintf(command,"#!/bin/bash \nvar1=$( cat %s | head -n 4 && ( cat %s | tail -n +5 | awk '{split( $0, a, \" \" ); asort( a ); for( i = 1; i <= length(a); i++ ) printf( \"%c%c \", a[i] ); printf( \"\\n\" ); }' | sort -n -k1,1 -k2 | uniq) )\nvar2=$( ( (echo \"$var1\" | tail -n +5 | cut -f 1 -d\" \") && (echo \"$var1\" | tail -n +5 | cut -f 2 -d\" \" ) ) | sort -n -k1,1 | uniq | awk '{for(i=p+1; i<$1; i++) print i} {p=$1}' )\necho \"$var1\" > %s\necho \"$var2\"| tr \"\\n\" \" \" > %s",path,path,'%','s',path,outfpath);
if(system(command)==-1){
fprintf(stderr,"Erreur à l'exécution de la commande \n%s\n",command);
}
//the first part only sorts the file and puts in outpath the list of the missing integers
//SECOND PART
long unsigned start=0,end=0,val,index=0;
long unsigned *intvals=calloc(MAX_INTS,sizeof(long unsigned));
FILE *f=fopen(outfpath,"r");
//reads the files and loads the missing ints to the array intvals
while(fscanf(f,"%lu ",&val)==1){
end=index;
intvals[index]=val;
index++;
}
if (index==0) return;
intvals=realloc(intvals,index*sizeof(long unsigned));
fclose(f);
free(command);
f=fopen(path,"r+w");
char *line=calloc(1000,sizeof(char));
command=calloc(1000,sizeof(char));
char *str;
long unsigned v1,v2,
d1=0,d2=0,
c=0,prec=-1,start_l=0;
int pos1, pos2;
//read a file containing two columns of ints
//for each pair v1 v2, count d1 d2,
//such as d1 is the number of missing values smaller than v1, d2 the number of missing values smaller than v2
//and overrwrite the line in the file using sed with the values v1-d1 and v2-d2
while(fgets(line,1000,f)!=NULL && line[0]=='#'){ continue; }
do{
str=strtok(line," \t");
v1=atoi(str);
str=strtok(NULL," \t");
v2=atoi(str);
if(prec!=v1) {
prec=v1;
d2=d1;
start_l=start;
}
for(index=start;index<=end;index++){
if(intvals[index]<v1){
d1++;
start++;
c=1;
}else{
start=d1;
break;
}
}
for(index=start_l;index<=end;index++){
if(intvals[index]<v2){
d2++;
start_l++;
c=1;
}else{
break;
}
}
if(c){
sprintf(command,"sed -i 's/%lu %lu/%lu %lu/' %s",v1,v2,v1-d1,v2-d2,path);
if(system(command)==-1){
fprintf(stderr,"Erreur à l'exécution de la commande \n%s\n",command);
}
}
c=0;
}while(fgets(line,1000,f)!=NULL);
fclose(f);
free(command);
free(line);
free(intvals);
}
int main(int argc,char* argv[]){
process_file(argv[1]);
return 0;
}
【问题讨论】:
-
@kvantour 我明白了,但问题是,在我看来,这很简单,我似乎没有找到有效的方法,我添加了我试图做的事情
-
@Inian 我添加了我尝试过的东西,它不起作用的原因是执行时间太长,因为我使用 sed 将每一行替换为新值,时间复杂度是 n^2,我正在寻找一种更有效的方法
-
我想我最大的问题是 - 为什么?您是否尝试创建特定的输出?然后忽略这个,只写那个输出。如果您具体要做的是根据规则编辑此文件,那么我并没有清楚地理解规则。
-
下面的答案中有一些好的想法。您选择在这组复杂的
c代码中调用sed表明您不熟悉awk。它使像您这样的任务能够在一个进程中处理所有任务,并将显着减少您的运行时间。使用 JohnBrown 的解决方案,您甚至可以使用内置功能来减少您的代码库。不确定您的数据是如何工作的,但希望您知道 *nix utilitytsort(地形排序)。它可能是您工具箱的另一个好工具。祝你好运! -
哦,还有 ++ 通过显示您的代码来改进您的 Q。祝你好运。
标签: linux bash shell awk command-line