前两天某个同学在科苑星空 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 fieldsexec 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 发现一个很有意思的东西:
矩阵用词
在中国大陆,横向称为“行”,纵向称为“列”。 在台湾,横向称为“列”,纵向称为“行”。
天那,要是用汉语和台湾同学讨论矩阵的话,该有多痛苦呀!
我想请教一下,如何使用awk实现把第一列去除,而保留其余的列(我所指的列,是以空格或者其他间隔符分隔的域).
谢谢!!
@wzl12356
用 awk 可能比较麻烦,用 sed 很简单的,原理就是把 leading space 和 word 去掉,例如:
sed -e 's/^ *//g;s/^\w*//g' file
第一个模式/^ */匹配开头的空格,删除开头空格后,第二个模式/^\w*/匹配开头的词。\w 代表数字字母或者下划线,可以根据您第一列的内容修改
正则表达式的模式可以参考 Wikipedia:http://en.wikipedia.org/wiki/Regular_expression
谢谢!!
试了一下,使用sed,可以满足要求.
哈哈 其实行列都是等价 没关系
再加个if就能算复数了。。。
用awk完全不麻烦,这里需要用到awk的行重构特性awk '{$1="";$0=$0;$1=$1;print}' input_file.txt$0=$0;$1=$1看似完全没有用,但是awk实际会用OFS将所有字段重新组合为$0,这样$1以及跟着的空白分割都去掉了。(另外先后顺序不能变)在单行处理中,实际上sed的性能虽然略强,但可读性远远比用awk或perl差,所以一般能不用sed还是不用。(除非你能保证以后绝对不会回来再改)