用 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 发现一个很有意思的东西:

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

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

《用 Vim 对矩阵转置》上有6条评论

  1. 我想请教一下,如何使用awk实现把第一列去除,而保留其余的列(我所指的列,是以空格或者其他间隔符分隔的域).
    谢谢!!

  2. @wzl12356
    用 awk 可能比较麻烦,用 sed 很简单的,原理就是把 leading space 和 word 去掉,例如:
    sed -e 's/^ *//g;s/^\w*//g' file
    第一个模式/^ */匹配开头的空格,删除开头空格后,第二个模式/^\w*/匹配开头的词。\w 代表数字字母或者下划线,可以根据您第一列的内容修改
    正则表达式的模式可以参考 Wikipedia:http://en.wikipedia.org/wiki/Regular_expression

  3. 用awk完全不麻烦,这里需要用到awk的行重构特性awk '{$1="";$0=$0;$1=$1;print}' input_file.txt$0=$0;$1=$1看似完全没有用,但是awk实际会用OFS将所有字段重新组合为$0,这样$1以及跟着的空白分割都去掉了。(另外先后顺序不能变)在单行处理中,实际上sed的性能虽然略强,但可读性远远比用awk或perl差,所以一般能不用sed还是不用。(除非你能保证以后绝对不会回来再改)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注