根据重复值合并列表

根据重复值合并列表

我对数据进行了这样的排序:

a
a f
b
c
c e
d
f z

本质上,这些行都是同一事物的别名列表,它们需要合并。这是简化的。如果在实际情况下很重要,我正在处理已移动的文件路径,并且需要知道哪些文件路径本质上是相同的。输入有 1 列用于初始文件,2 列用于文件重命名。寻找这样的输出:

a f z
b
c e
d

这是针对典型 Linux 系统上的 bash 脚本,因此任何大多数标准工具都可以。到目前为止,我已经尝试了处理该主题的其他问题中的一些 awk 脚本,但没有找到好的结果。

答案1

Awk解决方案:

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; next 
             } 
             a[$1] = $2; r[$2] = $1; 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file
  • NF == 2- 指示具有 2 个字段的记录的条件(NF- 字段总数)
  • a- 包含“独立”文件名(尚未重命名)的数组,例如初始文件名与其重命名版本之间的和或关系(b例如)da -> f
  • r- 包含相反关系的数组“重命名的文件名”->“初始文件名”(例如f -> a

输出:

a f z
b 
c e
d 

如果某些文件名可能被重命名多次 - 使用以下扩展解决方案:

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; r[$2] = r[$1];
             } 
             else { a[$1] = $2; r[$2] = $1 } 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file

答案2

gawk '
{
    arr[cnt][0] = $1    
    arr[cnt++][1] = $2  
}
END {
    for(i = 0; i < cnt; i++) {
        if(!arr[i][0]) continue

        next_name = arr[i][0]

        for(j = i; j < cnt; j++) {
            if(arr[j][0] != next_name) continue

            if(arr[j][1]) {
                next_name = arr[j][1]
                delete arr[j]
            }
            printf "%s ", next_name

        }
        print ""
    }
}' cnt=0 input.txt

输入(测试复杂)

u
a
a f
b
c
c e
d
c
f g
g a
a i
i j
a
a z
z w

输出

u 
a f g a i j 
b 
c e 
d 
c 
a z w 

相关内容