映射的子排序列表

Subsorting list of mappings

我有如下映射

mapping = [
    "key1",
    "key2",
    "key3",
    "key4",
    "key5#1",
    "key5#4",
    "key5#2",
    "key5#3",
    "key6#1",
    "key6#2"
]

和列表列表,例如[['val1', 'val2', 'val3', 'val4', 'val5', 'val6', 'val7', 'val8', 'val9' 'val10']] 我想以字典列表结束,例如

[{
    "key1": "val1",
    "key2": "val2",
    "key3": "val3",
    "key4": "val4",
    "key5": ["val5", "val7", "val8", "val6"],
    "key6": ["val9", "val10"],
}]

这样每个没有 # 的键只有 1 个值,而带有 # 的键有一个有序列表,按 # 之后的整数排序。我现在拥有的是:

for i in range(len(mapping)):
    if '#' in mapping[i]:
        result.setdefault(mapping[i].split('#')[0], []).append(row[i])
    else:
        result[mapping[i]] = row[i]

但是,这不会根据 # 之后的数字对值进行排序。

你可以在这里使用itertools.groupby。这个想法是使用映射中的键创建一个字典,最初每个键将被初始化为一个 None 的列表,其大小为一个键的重复次数。

from itertools import groupby
dct = {}
for k, g in groupby(mapping, lambda x: x.split('#')[0]):
    length = sum(1 for _ in g)
    dct[k] = [None] * length
...

现在 dct 看起来像:

>>> dct
{'key3': [None],
 'key2': [None],
 'key1': [None],
 'key6': [None, None],
 'key5': [None, None, None, None],
 'key4': [None]}

请注意,如果映射尚未排序,那么我们可以使用 mapping.sort(key=lambda x: x.split('#')[0]) 对其进行排序。这会将相似的键组合在一起。

上面的事情也可以通过首先识别每个键的计数然后使用计数初始化dict来完成。这样可以在 O(N) 时间内完成,以防 mapping 中的相似键尚未分组。

>>> from collections import Counter
>>> dct = {k: [None] * v  for k, v in Counter(
        key.split('#')[0] for key in mapping).items()}

现在我们可以遍历映射和列表并相应地更新 dct 中的值:

for key, value in zip(mapping, lst[0]):
    if '#' not in key:
        dct[key] = value
    else:
        key, index = key.split('#')
        # Simply assign the value to the index 
        dct[key][int(index)-1] = value
...
>>> dct
{'key3': 'val3',
 'key2': 'val2',
 'key1': 'val1',
 'key6': ['val9', 'val10'],
 'key5': ['val5', 'val7', 'val8', 'val6'],
 'key4': 'val4'}

这是你要的吗?

for i, key in enumerate(mapping):
    if '#' in key:
        key, order = key.split('#')
        result.setdefault(key, []).insert(int(order) - 1, row[i])
    else:
        result[key] = row[i]

备注:

  1. 使用enumerate - for i in range(len(something))被认为是坏习惯
  2. 在 Python3 中需要将 order 转换为 int - 插入采用 int,字符串无效。

听起来像是 groupby 和列表切片的工作。请注意,val9.

后的 row 中缺少逗号
def split_key(k):
    if '#' in k:
        return k.split('#')[0]
    else:
        return k

def group_keys(keys):
    for K, G in groupby(keys, key=split_key):
        yield split_key(K), sum(1 for g in G)

def slice_row(mapping, row):
    i = 0
    for key, length in group_keys(mapping):
        if length == 1:
            yield key, row[i]
        else:
            yield key, row[i:i + length]
        i += length

print(dict(slice_row(mapping, row[0])))

# >>> {'key4': 'val4', 'key6': ['val9', 'val10'], 'key5': ['val5', 'val6', 'val7', 'val8'], 'key3': 'val3', 'key1': 'val1', 'key2': 'val2'}