取消透视分隔字符串以获取父子关系

取消透视分隔字符串以获取父子关系

我有一个场景,需要反转数据以实现父子关系。我的源数据如下:

Key_Col|层次结构

1|a、b、c、d

2|a、b、c、d、e

我的预期输出如下:

关键校 孩子 家长
1 d C
1 C
1 A
1 A 无效的
2 e d
2 d C
2 C
2 A
2 A 无效的

您能否让我知道如何通过 bash 脚本实现此目的?

我使用的脚本是:

Var="1|a,b,c,d";
for i in $Var
do
 Key=`echo $i |cut -d'|' -f1`
 Hierarchy=`echo $i |cut -d'|' -f2`
 Delim_Count=`echo ${Hierarchy} |awk -F',' '{ print NF-1 }'`
 for (( c=$Delim_Count+1; c>=1; c-- ))
 do
   Parent=`echo ${Hierarchy} |cut -d',' -f$c`
   Prev=`expr $c - 1`
   if [ $Prev -ne 0 ]; then
    Child=`echo ${Hierarchy} |cut -d',' -f${Prev}`
    echo "${Key}|${Parent}|${Child}"
   else
    echo "${Key}|${Parent}|"
   fi
 done
done

但问题是,如果超过 100 行,脚本就需要很长时间才能完成。

答案1

使用用于处理文本或结构化数据的语言通常更容易完成此类事情。以下是使用标准文本处理实用程序的解决方案awk和使用磨坊主( mlr),专门用于处理结构化数据的工具(您的数据看起来像 CSV)。


awk

$ cat file
Key_Col|Hierarchy
1|a,b,c,d
2|a,b,c,d,e
$ awk 'BEGIN { OFS=FS="|" } NR == 1 { print $1, "Child", "Parent"; next } { n=split($2,a,","); a[0]="null"; for (i=n;i>0;i--) print $1,a[i],a[i-1] }' file
Key_Col|Child|Parent
1|d|c
1|c|b
1|b|a
1|a|null
2|e|d
2|d|c
2|c|b
2|b|a
2|a|null

上面的代码awk将每个输入行读取为一组|- 分隔的字段。它将逗号上的第二个字段拆分到数组中a。数组的第 0 个元素设置为字符串null(split()创建一个第一个索引为 1 的数组,所以我们知道我们可以使用索引 0 而不会覆盖数据)。然后,我们从数组末尾迭代到开头,输出第一个字段的值以及当前数组元素和数组中的前一个元素。当我们到达最后一次迭代时,循环变量的值为 1,这会导致打印a[1]and a[0]( ) 。null

包含标题的第一行输入的处理方式有所不同。该代码不是拆分等,而是打印三个字段:输入中的第一个字段以及字符串Child和各一个字段Parent。条件NR==1块执行此操作。

为了可读性而重新格式化的代码awk

BEGIN {
    OFS = FS = "|"
}

NR == 1 {
    print $1, "Child", "Parent"
    next
}

{
    n = split($2, a, ",")
    a[0] = "null"
    for (i = n; i > 0; i--)
        print $1, a[i], a[i-1]
}

由于输入看起来像 CSV,因此使用支持 CSV 的工具来处理它可能会更安全。 Miller( mlr) 就是这样一个工具:

$ mlr --csv --fs pipe put -q 'm=splitnv($Hierarchy,","); m[0]="null"; for (var i=length(m)-1;i>0;i-=1) { emit {"Key_Col": $Key_Col, "Child": m[i], "Parent": m[i-1] } }' file
Key_Col|Child|Parent
1|d|c
1|c|b
1|b|a
1|a|null
2|e|d
2|d|c
2|c|b
2|b|a
2|a|null

Millerput表达式遵循与上述代码相同的轮廓awk,但不必将标头作为特殊情况处理,因为 Miller 知道如何读取和使用这些标头:

m = splitnv($Hierarchy, ",")
m[0] = "null"

for (var i = length(m) - 1; i > 0; i -= 1) {
    emit {
        "Key_Col": $Key_Col,
        "Child": m[i],
        "Parent": m[i-1]
    }
}

putMiller 允许我们通过调整子命令之前的选项来产生多种不同形式的结果。

漂亮打印的“禁止”输出:

$ mlr --c2p --barred --ifs pipe put ...as above...
+---------+-------+--------+
| Key_Col | Child | Parent |
+---------+-------+--------+
| 1       | d     | c      |
| 1       | c     | b      |
| 1       | b     | a      |
| 1       | a     | null   |
| 2       | e     | d      |
| 2       | d     | c      |
| 2       | c     | b      |
| 2       | b     | a      |
| 2       | a     | null   |
+---------+-------+--------+

JSON:

$ mlr --c2j --ifs pipe put ...as above...
{ "Key_Col": 1, "Child": "d", "Parent": "c" }
{ "Key_Col": 1, "Child": "c", "Parent": "b" }
{ "Key_Col": 1, "Child": "b", "Parent": "a" }
{ "Key_Col": 1, "Child": "a", "Parent": "null" }
{ "Key_Col": 2, "Child": "e", "Parent": "d" }
{ "Key_Col": 2, "Child": "d", "Parent": "c" }
{ "Key_Col": 2, "Child": "c", "Parent": "b" }
{ "Key_Col": 2, "Child": "b", "Parent": "a" }
{ "Key_Col": 2, "Child": "a", "Parent": "null" }

(ETC。)

答案2

使用(以前称为 Perl_6)

~$ raku -e 'my @a; for lines() {.split("|") andthen @a.push: .[0] => ("null".Slip, .[1].split(",").Slip) };  \
            put .invert.invert.join("\n") for [Z=>] @a.map(*.key), @a.map(*.value.rotor(2 => -1) );'   file

上面是用 Raku(Perl 编程语言家族的成员)编写的答案。简而言之,在第一条语句中声明了一个数组。在第二条语句中,通过首先在bar 上获取键来lines()读取“哈希数组” ,然后用逗号分割值。 A添加到每个值系列的开头。由于 Raku 不会自动展平数组元素(值得庆幸的是),展平是通过调用.在最后的语句中,“空”填充的值被重叠地填充,每行的键和值被压缩成对,被编辑两次以将键扩展到每个关联的值,然后用or打印。split|,"null".Sliprotor[Z=>]invertsayput

输入示例:

1|a,b,c,d
2|a,b,c,d,e
3|a,b,c

示例输出(非反转列):

1   null a
1   a b
1   b c
1   c d
2   null a
2   a b
2   b c
2   c d
2   d e
3   null a
3   a b
3   b c

.skip如果您需要处理标题行,一种简单的方法是添加对after的调用lines(默认跳过一行),然后使用 重新添加您选择的标题say()

最后,OP的要求实际上是颠倒列的顺序,这可以通过在最后一个语句中插入调用来完成,编写as.reverse的最终准备工作。@a.map(*.value.rotor(2 => -1)@a.map(*.value.reverse.rotor(2 => -1)

示例输出(反转列):

1   d c
1   c b
1   b a
1   a null
2   e d
2   d c
2   c b
2   b a
2   a null
3   c b
3   b a
3   a null

https://raku.org

相关内容