用 Vim 对矩阵转置

前两天某个同学在科苑星空 BBS 上问到了一个有趣的问题:如何在 Vim 中对矩阵进行转置?

我当时想,转置不就是行列互换嘛,awk 可以取一列,那么拿出来每列然后打印成一行不就好了?类似于:

echo `awk '{printf "%s ",$1}' file`
echo `awk '{printf "%s ",$2}' file`
echo `awk '{printf "%s ",$3}' file`
...

本来觉得用 bash 写一个循环语句就可以了,但是怎么也尝试不出来如何替换那个 $1, $2, $3...就想没办法了只能搞 eval 了。但是我觉得这种事情 Unix 前辈们应该干过,所以就搜了一斧子,果然搜到了一个 AWK 程序,《Sed & Awk》 Ch13.9 Perform a Matrix Transposition:

#! /bin/sh
# Transpose a matrix: assumes all lines have same number of fields

exec awk '
NR == 1 {
    n = NF
    for (i = 1; i <= NF; i++)
        row[i] = $i
    next
}
{
    if (NF > n)
        n = NF
    for (i = 1; i <= NF; i++)
        row[i] = row[i] " " $i
}
END {
    for (i = 1; i <= n; i++)
        print row[i]
}' ${1+"$@"}

哈,除了觉得这样内存占用可能比较大之外,这可是一个相当不错的程序。

在 Vim 中调用就很简单了,将上面脚本保存成 transpose,加上可执行属性放在某个可执行路径下(比如 ~/bin),然后在 Vim 编辑矩阵文件时 :%!transpose 就可以了。

PS: 另外,在查证矩阵的“转置”应该写成“转秩”还是“转置”时,我在 Wikipedia 发现一个很有意思的东西:

矩阵用词
在中国大陆,横向称为“行”,纵向称为“列”。 在台湾,横向称为“列”,纵向称为“行”。

天那,要是用汉语和台湾同学讨论矩阵的话,该有多痛苦呀!