给定一个包含两列整数的文件,我想消除整数值之间的差距。间隙我的意思是,如果我们取两个整数 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 减少了 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; 
}     

请您参考如下方法:

这可能会做到:

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 

file有作为输入:
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 

这种方法的想法是跟踪一个数组 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 


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!