文件中的递归键值

时间:2014-12-17 05:39:59

标签: python bash awk grep

有一个文件有两个列[可以理解为键和值]:

k1 v1
k2 v2
k3 v3
k4 k1
k5 k4

现在我希望从这个文件输出这样的内容:

k1 v1
k2 v2
k3 v3
k4 k1 v1
k5 k4 k1 v1

如果某个键的值是另一个键,则将该值转换为该行。怎么可以接近

这可能是多值键以及k1 v1和k1 x1。对于多值键,希望有一个包含两个值的新行:

k1 v1
k1 x1
k2 k1 

的更改
k1 v1
k1 x1
k2 k1 v1
k2 k1 x1

6 个答案:

答案 0 :(得分:1)

python代码:

from collections import OrderedDict
dict = {}
fp = open('test.txt')
for line in fp.readlines():
    line = line.split(" ")
    dict[line[0]] = line[1].replace('\n','')
fp.close() 
dict = OrderedDict(sorted(dict.items(), key=lambda t: t[0]))
for key in dict:
    if dict.has_key(dict[key]):
        print key,dict[key],dict[dict[key]]
    else:
        print key,dict[key]

源文件:

k1 v1
k2 v2
k3 v3
k4 k1
k5 k4
k6 k2
k7 v8

结果:

k1 v1
k2 v2
k3 v3
k4 k1 v1
k5 k4 k1
k6 k2 v2
k7 v8

答案 1 :(得分:0)

这样的东西
$  awk '($2 in hash){hash[$1]=$2" "hash[$2]; next} {hash[$1]=$2} END{for (i in hash) print i, hash[i]}' input
k1 v1
k2 v2
k3 v3
k4 k1 v1
k5 k4 k1 v1

答案 2 :(得分:0)

这个答案解决了这个问题的第一个版本,其中的键是单值的。

$ awk '{d[$1]=$2" "d[$2]; print $1,d[$1]}' file
k1 v1 
k2 v2 
k3 v3 
k4 k1 v1 
k5 k4 k1 v1 

如何运作

  • d[$1]=$2" "d[$2]

    对于每一行,都会将一个项目添加到字典中。关键是第一列。该值由第二列给出,并以空格分隔,字典中对应于第二列的任何条目。

  • print $1,d[$1]

    对于每一行,都会打印第一列和相应的字典值。

评论

这会打印出遇到的每一行的结果。这保证了键的输出顺序与输入文件的顺序相同。

此方法在每行的末尾打印一个额外的空格。如果这是一个问题,可以很容易地将其删除。

答案 3 :(得分:0)

dict={}
x1=fileobject.read()
for line in x1.splitlines():
    if line.split()[1] in dict.keys():
        dict[line.split()[0]]=line.split()[1]+" "+dict[line.split()[1]]
    else:
        dict[line.split()[0]]=line.split()[1]

print dict

通过这种方式,您可以根据需要使用带有键的对象字典。

输出:{'k3': 'v3', 'k2': 'v2', 'k1': 'v1', 'k5': 'k4 k1 v1', 'k4': 'k1 v1'}

答案 4 :(得分:0)

了解您的更新要求

在Awk中

awk '{for(i=(b[$2]>0);i<=b[$2];i++){c[$1" "++b[$1]]=$2" "c[$2" "i];print $1,c[$1" "b[$1]]}}' file

实施例

input

k1 v1
k1 x1
k1 y1
k2 k1
k2 k4
k3 k2

output

k1 v1
k1 x1
k1 y1
k2 k1 v1
k2 k1 x1
k2 k1 y1
k2 k4
k3 k2 k1 v1
k3 k2 k1 x1
k3 k2 k1 y1
k3 k2 k4

答案 5 :(得分:0)

只需调整一下这个答案:

https://stackoverflow.com/a/25085230/1745001

打印下降中的每个节点,而不仅仅是根节点和叶节点。例如,这将处理潜在的无限递归,例如,如果您的输入文件包含k1 k2k2 k1,并且将按照输入文件中键出现的顺序打印输出:

$ cat tst.awk
function descend(node,  child, descendants) {
    stack[node]
    child = map[node]
    if (child in map) {
        if (child in stack) {
            descendants = node "*"
        }
        else {
            descendants = child " " descend(child)
        }
    }
    else {
        descendants = child
    }
    delete stack[node]
    return descendants
}
{ keys[++numKeys] = $1; map[$1] = $2 }
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        print key, descend(key)
    }
}

$ awk -f tst.awk file
k1 v1
k2 v2
k3 v3
k4 k1 v1
k5 k4 k1 v1

关于处理k1 v1k1 x1的问题的第2部分 - 只需调整上面的内容即可使用2D数组或带有空格分隔键值或类似字符串的数组而不是上面的1D map数组,如:

{
    if (!seen[$1]++) {
        keys[++numKeys] = $1
    }
    map[$1,++cnt[$1]] = $2
}

并修改descend()函数以循环map []

的内容
for (i=1; i<=cnt[node]; i++) {
    child = map[node,i]
    if (child in map) {
        ...
    }
}

而不是当前的简单分配:

child = map[node]
if (child in map) {
    ...
}

这可能并不完美,因为它未经测试但是它是正确的想法并且会很接近并且不应该太难以进行调试(即我不会去!)。