有条件地用列名替换单元格值

时间:2011-11-11 18:36:39

标签: perl sed awk

我有一个165 x 165等级矩阵,每行的值为1-165。我想解析每一行并删除所有值> = 5,按递增顺序对每一行进行排序,然后将值1-5替换为原始矩阵中列的名称。

例如,对于行k,值1,2,3,4将在前两次转换后生成,并将替换为p,d,m,n,a。

2 个答案:

答案 0 :(得分:1)

我假设你的数组包含一个数组数组......

Awk,Sed或Perl都没有多维数组。但是,可以使用数组数组在Perl中模拟它们。

$a[0]->[0] = xx;
$a[0]->[1] = yy;
[...]
$a[0]->[164] = zz;

$a[1]->[0] = qq;
$a[1]->[1] = rr;
[...]
$a[164]->[164] = vv;

这有意义吗?

我正在调用行$x和列$y,因此数组中的元素将为$array[$x]->[$y]。这样好吗?

好的,您的列名将位于行$array[0]中,因此如果我们在$array[$x]->[$y]中找到小于5的值,则我们知道列名称位于$array[0]->[$y]中。这样好吗?

for my $x (1..164) { #First row is column names
  for my $y (0..164)  {
    if ($array[$x]->[$y] <= 5) {
        $array[$x]->[$y] = $array[0]->[$y];
    }
  }
}

我只是遍历所有行,每行,所有列,并检查值。如果该值小于或等于5,我将其替换为列名。

我希望我不会为你做功课。

答案 1 :(得分:1)

这个GNU sed解决方案可能有用,虽然它需要扩展,因为我只使用10x10矩阵进行测试:

# { echo {a..j};for x in {1..10};do seq 1 10 | shuf |sed 'N;N;N;N;N;N;N;N;N;s/\n/ /g';done; }> test_data
# cat test_data                                                                                 
a b c d e f g h i j
4 5 9 3 6 2 10 8 7 1
3 7 4 2 1 6 10 5 8 9
10 9 3 1 2 7 8 5 6 4
5 10 4 9 7 8 1 3 6 2
8 6 5 9 1 4 3 2 7 10
2 8 9 3 5 6 10 1 4 7
3 9 8 2 1 4 10 6 7 5
3 7 2 1 8 6 10 4 5 9
1 10 8 3 6 5 4 2 7 9
7 2 3 5 6 1 10 4 8 9
# cat test_data |
sed -rn '1{h;d};s/[0-9]{2,}|[6-9]/0/g;G;s/\n|$/ &/g;s/$/&1 2 3 4 5 /;:a;s/^(\S*) (.*\n)(\S* )(.*)/\2\4\1\3/;ta;s/\n//;s/0[^ ]? //g;:b;s/([1-5])(.*)\1(.)/\3\2/;tb;p'
j f d a b      
e d a c h      
d e c j h      
g j h c a      
e h g f c      
h a d i e      
e d a f j      
d c a h i      
a h d g f      
f b c h d   

sed命令的工作原理如下。

数据文件的第一行包含列标题存储在保留空间中,然后删除模式空间(当前行)。对于所有后续数据行,所有两个或更多数字数字以及值6到9将转换为0.附加列名称以及数据值的换行符。在换行符和字符串结尾之前插入空格。将数据转换为查找,并将排序的值(即1 2 3 4 5)添加到其中。删除换行符以及任何0值和关联的查找。值1到5将替换为查找中的列名。

编辑:

我可能误解了有关排序列或行的问题,如果是这样,这是一个最小的修复 - 用原始值替换1 2 3 4 5并在使用查找中的列名替换数字数据之前执行数字排序。

相关问题