根据其他列值将一列转置为行

时间:2015-10-05 03:13:46

标签: unix transpose

我想根据另一列的值来转移几个较小部分的列,例如

1 ID1  V1  
2 ID1  V2  
3 ID1  V3  
4 ID2  V4  
5 ID2  V5  
6 ID3  V6  
7 ID3  V7  
8 ID3  V8  
9 ID3  V9  

我希望每个ID的所有V值都在一行中,例如

ID1 V1 V2 V3  
ID2 V4 V5  
ID3 V6 V7 V8 V9

每个id都有不同的行数进行转置,如示例所示。如果使用序列号列更容易执行此操作,那也没关系。

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

这是一个简单的awk单线程来完成这个技巧:

awk '1 {if (a[$2]) {a[$2] = a[$2]" "$3} else {a[$2] = $3}} END {for (i in a) { print i,a[i]}}' file.txt

输出:

ID1 V1 V2 V3
ID2 V4 V5
ID3 V6 V7 V8 V9

答案 1 :(得分:0)

如果您喜欢使用Javascript进行编码,请使用jline在命令行中执行此操作:https://github.com/bitdivine/jline/

mmurphy@violet:~$ cat ,,, | jline-foreach 'begin::global.all={}' line::'fields=record.split(/ +/);if(fields.length==3)tm.incrementPath(all,fields.slice(1))' end::'tm.find(all,{maxdepth:1},function(path,val){console.log(path[0],Object.keys(val).join(","));})' ID1 V1,V2,V3 ID2 V4,V5 ID3 V6,V7,V8,V9

输入为: mmurphy@violet:~$ cat ,,, 1 ID1 V1 2 ID1 V2 3 ID1 V3 4 ID2 V4 5 ID2 V5 6 ID3 V6 7 ID3 V7 8 ID3 V8 9 ID3 V9 mmurphy@violet:~$

说明:这会构建一个树,其中第一级分支是用户ID,第二级是V(版本?)。您可以为任意数量的级别执行此操作。树叶只是柜台。首先我们创建一个空树:

'begin::global.all={}'

然后进入的每一行都分为计数器,ID和版本号。计数器被切掉,只留下数组[userID,version]。 incrementCounter在树中创建那些分支,有点像mkdir -p,并递增叶计数器,尽管你实际上并不需要知道每个用户,版本组合的频率:

line::'fields=record.split(/ +/);if(fields.length==3)tm.incrementPath(all,fields.slice(1))' end::'tm.find(all,{maxdepth:1},function(path,val){console.log(path[0],Object.keys(val).join(","));})'

最后我们有tm.find,其行为与UNIX相似,并打印树中的每个路径。除此之外,我们将搜索深度限制为所需的细分(1,但如果您像我一样,那么您希望接下来分解2,3,5或8个变量)。这样您就可以将细分和值列表分开,然后打印出答案。

如果你永远不需要更深层次的细分,你可能会想要坚持使用awk,因为它可能是预先安装的。