在列中查找唯一值,并将唯一值替换为数字

时间:2014-05-09 13:52:00

标签: perl unix replace awk

我有一个标签限制数据,内容为

1 0 0 1 1 Black Swan
0 0 1 0 0 Golden Duck
1 0 0 1 0 Brown Eagle
0 0 1 0 1 Golden Duck
1 0 0 1 0 Black Swan
1 0 1 0 0 Golden Duck
1 0 0 1 1 Sparrow

最后一列是由空格分隔的一个或多个单词的组合。我想计算最后一列中唯一值的数量,并将其替换为该组唯一的数字。我知道我可以使用

计算和列出数字
awk -F '\t' '{print $NF}'  infile | sort | uniq | wc -l

但我如何用数字代替? 例如,将所有黑天鹅替换为1,将所有金鸭替换为2等。我希望结果为:

1 0 0 1 1 1
0 0 1 0 0 2
1 0 0 1 0 3
0 0 1 0 1 2
1 0 0 1 0 1
1 0 1 0 0 2
1 0 0 1 1 4

我还希望生成给定特定值的数字列表,例如

Black Swan 1
Golden Duck 2
Brown Eagle 3
Sparrow 4

3 个答案:

答案 0 :(得分:5)

您可以使用关联数组为每个不同的名称递增计数器:

awk '
    BEGIN { 
        FS = OFS = "\t" 
        i = 0
    }
    {
        if (! names[$NF]) {
            names[$NF] = ++i
        }
        $NF = names[$NF]
        print $0
    }
    END {
        for (name in names) {
            printf "%s %d\n", name, names[name]
        }
    }
' infile

它产生:

1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Golden Duck 2
Brown Eagle 3
Sparrow 4
Black Swan 1

答案 1 :(得分:4)

我开始写这篇文章,所以我会完成:

awk '
BEGIN {FS = OFS = "\t"}
{
    last[$NF] = (last[$NF] ? last[$NF] : ++cnt)
    $NF = last[$NF]
    line[NR] = $0
}
END {
    for (nr=1; nr<=NR; nr++) 
        print line[nr]
    for (name in last) 
        print name, last[name]
}' file
1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Brown Eagle     3
Black Swan      1
Sparrow         4
Golden Duck     2

更新:

以下是perl替补:

perl -F'\t' -lane '
    $h{$F[-1]} = ++$c unless exists $h{$F[-1]}; 
    $F[-1] = $h{$F[-1]}; 
    print join "\t", @F }{ print "$_  $h{$_}" for keys %h
' file
1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Golden Duck  2
Brown Eagle  3
Black Swan  1
Sparrow  4

以下是基于mpapec's优秀评论的另一个更新:

perl -F'\t' -lane '
    $F[-1] = $h{$F[-1]} ||= ++$c; 
    print join "\t", @F }{ print "$_  $h{$_}" for keys %h
' file 

答案 2 :(得分:1)

您要做的是创建一组唯一数据。 set是一个包含所有唯一元素的字典或哈希表。创建集后,您可以搜索它并用适当的值替换字符串。

以下是帮助您解决问题的其他链接:

http://world.std.com/~swmcd/steven/perl/pm/set.html