如何将数据转换为包含列表列表的字典?

Jes*_*ess 4 python dictionary list python-3.x

values/test/10/blueprint-0.png,2089.0,545.0,2100.0,546.0
values/test/10/blueprint-0.png,2112.0,545.0,2136.0,554.0
Run Code Online (Sandbox Code Playgroud)

我想要做的是读取一个.txt包含数百个值的文件,比如上面分享的值,创建一个字典,其密钥是前两个数字的值; 我的预期输出:

mydict = {
    '10-0': [[2089,545,2100,545,2100,546,2089,546], 
             [2112,545,2136,545,2136,554,2112,554]],
}
Run Code Online (Sandbox Code Playgroud)

说明我们如何从4号去到8位数字,让我们看到他们x1,y1,x2,y2在第一,并且在输出它们合并为x1,y1,x2,y1,x2,y2,x1,y2

在实际数据中,我有数百个值,所以如果起始2个元素不同,我会有不同的键.假设.txt文件中的行开头,values/test/10/blueprint-1.png那么键是'10-1'.

我尝试过的:

import re

import itertools

file_data = [re.findall('\d+', i.strip('\n')) for i in open('ground_truth')]
print(file_data)
final_data = [['{}-{}'.format(a, b), list(map(float, c))] for a, b, *c in file_data]
new_data = {a: list(map(lambda x: x[-1], b)) for a, b in
            itertools.groupby(sorted(final_data, key=lambda x: x[0]), key=lambda x: x[0])}
Run Code Online (Sandbox Code Playgroud)

但我得到了

ValueError: not enough values to unpack (expected at least 2, got 1)
Run Code Online (Sandbox Code Playgroud)

我似乎无法解决我的问题从一个简单的文件,其中包含这两行中的答案mydict.

请注意,以此行为例,values/test/10/blueprint-0.png,2089.0,545.0,2100.0,546.0我们将找到这些数字,[10, 0, 2089, 0, 545, 0, 2100, 0, 546, 0]并且0元素3,5,7和9中的s是无关紧要的,因为这些数字在列表中.这些可以通过打印看到file_data,就像我在上面的代码中所做的那样.

Mar*_*ers 5

您需要使用更复杂的正则表达式来忽略小.0数值:

re.findall(r'(?<!\.)\d+', i)
Run Code Online (Sandbox Code Playgroud)

这使用负面的后视,忽略任何前面带有数字的数字..这将忽略.0,但如果有.01,那么.0(或.<digit>)之外的那些额外数字仍将被拾取.对于您的输入应该足够了.

我在这里使用常规循环来使代码更具可读性,并保持代码O(N)而不是O(NlogN)(不需要排序):

new_data = {}
with open('ground_truth') as f:
    for line in f:
        k1, k2, x1, y1, x2, y2 = map(int, re.findall(r'(?<!\.)\d+', line))
        key = '{}-{}'.format(k1, k2)
        new_data.setdefault(key, []).append([x1, y1, x2, y1, x2, y2, x1, y2])
Run Code Online (Sandbox Code Playgroud)

x, y在这里硬编码你的组合,因为你似乎有一个非常具体的期望订单.

演示:

>>> import re
>>> file_data = '''\
... values/test/10/blueprint-0.png,2089.0,545.0,2100.0,546.0
... values/test/10/blueprint-0.png,2112.0,545.0,2136.0,554.0
... '''
>>> new_data = {}
>>> for line in file_data.splitlines(True):
...     k1, k2, x1, y1, x2, y2 = map(int, re.findall(r'(?<!\.)\d+', line))
...     key = '{}-{}'.format(k1, k2)
...     new_data.setdefault(key, []).append([x1, y1, x2, y1, x2, y2, x1, y2])
...
>>> new_data
{'10-0': [[2089, 545, 2100, 545, 2100, 546, 2089, 546], [2112, 545, 2136, 545, 2136, 554, 2112, 554]]}
Run Code Online (Sandbox Code Playgroud)

一个很好的选择是将输入文件视为CSV格式!使用该csv模块是拆分列的好方法,之后您只需要处理第一个文件名列中的数字:

import csv, re

new_data = {}
with open('ground_truth') as f:
    reader = csv.reader(f)
    for filename, *numbers in reader:
        k1, k2 = re.findall(r'\d+', filename)  # no need to even convert to int
        key = '{}-{}'.format(k1, k2)
        x1, y1, x2, y2 = (int(float(n)) for n in numbers)
        new_data.setdefault(key, []).append([x1, y1, x2, y1, x2, y2, x1, y2])
Run Code Online (Sandbox Code Playgroud)