Python: разбиение словаря на меньшие словари по ключам (кортеж) - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть словарь, где ключи - это кортежи из двух целых чисел (x,y), а значения - это строки.

Как разделить этот словарь на меньшие словари, где разделение определяется тем, больше ли значение y, чем какое-либо пороговое значение?

Например, скажем, у меня есть ключи(значения словаря не имеют значения, поэтому я здесь их опускаю)

(0, 2), (0, 4), (0, 10), (0, 3), (0, 11), (0, 20), (0, 8), (0, 14)

и говорю, что у меня есть пороги 0, 5, 10, 15.

Тогда одно разбиение должно состоять из словаря со следующими ключами:

(0,2), (0,4), (0,3)

, поскольку все значения y больше 0, но не больше5.

Тогда в следующем словаре должны быть ключи

(0,8)

, поскольку он больше 0 и 5, но не больше 10.

Тогда у нас есть (0, 10), (0, 11), (0, 14)

, поскольку оно больше (или равно) 0, 5, 10, но не 15.

Наконец, у нас есть (0, 20) само по себе.

Ответы [ 4 ]

0 голосов
/ 30 ноября 2018

Этот метод кажется мне самым простым, хотя, конечно, он не самый быстрый:

d1 = {(k1,k2):v for (k1,k2),v in d.items() if 0<k2<=5}
d2 = {(k1,k2):v for (k1,k2),v in d.items() if 5<k2<=10}
d3 = {(k1,k2):v for (k1,k2),v in d.items() if 10<k2<=15}
d4 = {(k1,k2):v for (k1,k2),v in d.items() if 15<k2}

Или объединить так:

bounds = 0, 5, 10, 15, 1_000_000
bounds_dicts = {(b1,b2):{(k1,k2):v for (k1,k2),v in d.items() if b1<k2<=b2}
                for (b1,b2) in zip(bounds[:-1],bounds[1:])}

Опять же, это будет неэффективно.Словарь повторяется один раз для каждого нового словаря.Но для небольших проблем это должно быть хорошо.

0 голосов
/ 30 ноября 2018

Вы можете использовать collections.defaultdict, повторять и обновлять ключи, определенные границами сегмента.Это лучшая идея, чем создание переменного числа переменных.

d = {(0, 2): 1, (0, 4): 2, (0, 10): 3, (0, 3): 4,
     (0, 11): 5, (0, 20): 6, (0, 8): 7, (0, 14): 8}

L = [0, 5, 10, 15, float('inf')]  # include infinite to facilitate later comparisons

from collections import defaultdict

dd = defaultdict(dict)

for k, v in d.items():
    for i, j in zip(L, L[1:]):
        if i <= k[1] < j:
            dd[i].update({k: v})
            break

print(dd)

defaultdict(dict,
            {0: {(0, 2): 1, (0, 3): 4, (0, 4): 2},
             5: {(0, 8): 7},
             10: {(0, 10): 3, (0, 11): 5, (0, 14): 8},
             15: {(0, 20): 6}})

Алгоритм можно улучшить, используя bisect вместо последовательного повторения границ в L.

0 голосов
/ 30 ноября 2018

Это должно работать.

original_dict = {(0, 2):"a", (0, 4):"b", (0, 10):"c",
 (0, 3):"d", (0, 11):"e", (0, 20):"f", (0, 8):"g", (0, 14):"h"}

thresholds = [0, 5, 10, 15]
thresholds = sorted(thresholds,reverse=True)
new_dict_of_dicts = {} #threshold: dict
for threshold in thresholds:
    new_dict_of_dicts[threshold] = {}
    for key in list(original_dict.keys()):
        if key[1] > threshold:
            new_dict_of_dicts[threshold][key] = original_dict.pop(key)

print(new_dict_of_dicts) 
#{15: {(0, 20): 'f'}, 10: {(0, 11): 'e', (0, 14): 'h'}, 5: {(0, 10): 'c', (0, 8): 'g'}, 0: {(0, 2): 'a', (0, 4): 'b', (0, 3): 'd'}}
0 голосов
/ 30 ноября 2018

Конечно, это можно написать гораздо лучше, но вы должны понять.Просто перебирайте dict и проверяйте значение y ключа на соответствие различным условиям, которые вы можете определить или сгенерировать динамически.

thing = {
    (1,2): 'a',
    (2,19): 'b'
}

d1 = {}
d2 = {}
for k, v in thing.items():
    // while iterating through the original dict, write some logic to determine how you want to split up based on the y values.
    if k[1] < 5:
        d1[k] = v
    if k[1] < 10:
        d2[k] = v

print(d1, d2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...