根据另一列值将一列转置为行
Transpose one column to rows based on another column values
我想根据另一列的值将一列转置为几个较小的部分,例如
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 都有不同的行数要转置,如示例所示。如果使用序列号列更容易执行此操作,那也很好。
有人能帮忙吗?
如果您喜欢在 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,因为它可能是预安装的。
这是一个简单的 awk 单行代码:
awk '1 {if (a[]) {a[] = a[]" "} else {a[] = }} END {for (i in a) { print i,a[i]}}' file.txt
输出:
ID1 V1 V2 V3
ID2 V4 V5
ID3 V6 V7 V8 V9
我想根据另一列的值将一列转置为几个较小的部分,例如
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 都有不同的行数要转置,如示例所示。如果使用序列号列更容易执行此操作,那也很好。
有人能帮忙吗?
如果您喜欢在 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,因为它可能是预安装的。
这是一个简单的 awk 单行代码:
awk '1 {if (a[]) {a[] = a[]" "} else {a[] = }} END {for (i in a) { print i,a[i]}}' file.txt
输出:
ID1 V1 V2 V3
ID2 V4 V5
ID3 V6 V7 V8 V9