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

2024-04-24 16:46:05 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我要做的是读取一个.txt文件,其中包含数百个值,就像上面共享的值一样,以创建一个字典,其中的键是其中前2个数字的值;我的预期输出:

mydict = {
    '10-0': [[2089,545,2100,545,2100,546,2089,546], 
             [2112,545,2136,545,2136,554,2112,554]],
}

为了解释我们是如何从4个数变成8个数的,我们首先把它们看作x1y1x2y2,在输出中它们被组合成x1y1x2y1x2y2x1y2

在实际数据中,我有数百个值,因此如果开始的两个元素不同,我将有不同的键。假设.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])}

但是我得到了

ValueError: not enough values to unpack (expected at least 2, got 1)

我似乎无法从一个包含这两行的简单文件中修复问题,从而得到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]和元素3、5、7和9中的0是不相关的,因为这些数字在一个列表中。这些可以通过打印file_data看到,就像我在上面的代码中所做的那样。你知道吗


Tags: 文件lambdaintestfordatapng数字
1条回答
网友
1楼 · 发布于 2024-04-24 16:46:05

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

re.findall(r'(?<!\.)\d+', i)

这将使用一个负数,忽略前面有.的任何数字。这将忽略.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])

我在这里硬编码了您的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]]}

一个很好的替代方法就是把你的输入文件当作CSV格式!使用csv模块是分割列的好方法,之后只需处理第一个filename列中的数字:

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])

相关问题 更多 >