python: отфильтровать список dict на основе другого списка dict - PullRequest
1 голос
/ 16 июня 2020

У меня два списка диктовок. Давайте назовем первый как dd:

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '3', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

Ключевые особенности элемента dict: id ie 11,22,33 и priority ie 1,2,3..

Другой dict - это фильтр dict:

filter_dict = [{'11': 2}, {'33': 2}]

Этот фильтр dict имеет key-value, где key определяет id в первом dict dd, а значение означает количество элементов, которые должны быть выбраны из первого dict dd, т.е. {'11': 2} означает выбор верхних 2 элементов из dd на основе priority. И выберите только 1 элемент с высшим приоритетом из dd, если filter_dct не имеет соответствующего id в нем.

То, что у меня есть до сих пор, - это способ получить только 1 элемент с высшим приоритетом из dd на основе priority:

tmp = {}
for elem in dd:
    tmp.setdefault([*elem][0], []).append(elem)
out = [subl[0] for subl in tmp.values()]
print(out)

Желаемый результат, которого я пытаюсь достичь:

res = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
          {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
          {'22': {'xx': '300', 'priority': '1', 'channels': '40'}}, # one elem because no record in the filter_dict
          {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
          {'33': {'xx': '500', 'priority': '2', 'channels': '30'}}]

EDIT:

Предлагаемые решения терпят неудачу, когда элементов больше 4.

т.е. для входа:

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '4', 'channels': '35'}},
      {'11': {'xx': '260', 'priority': '9', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '11', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

на выходе:

[{'11': {'xx': '259', 'priority': '1', 'channels': '55'}}, {'11': {'xx': '270', 'priority': '11', 'channels': '35'}}, {'11': {'xx': '260', 'priority': '2', 'channels': '35'}}, {'22': {'xx': '300', 'priority': '1', 'channels': '40'}}, {'33': {'xx': '400', 'priority': '1', 'channels': '40'}}]

Что неверно.

Ответы [ 4 ]

2 голосов
/ 16 июня 2020

это сработало для меня:

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '3', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

filter_dict = [{'11': 2}, {'33': 2}]

res = []

for dd_one_dic in dd:
    for dir_id, priority in dd_one_dic.items():
        if priority['priority'] == '1':
            res.append(dd_one_dic)
        else:
            for filter_one_dic in filter_dict:
                if dir_id == list(filter_one_dic.keys())[0]: 
                    if int(priority['priority']) <= filter_one_dic[list(filter_one_dic.keys())[0]]:
                        res.append(dd_one_dic)

print(*res, sep = '\n')

Вывод

{'11': {'xx': '259', 'priority': '1', 'channels': '55'}}
{'11': {'xx': '260', 'priority': '2', 'channels': '35'}}
{'22': {'xx': '300', 'priority': '1', 'channels': '40'}}
{'33': {'xx': '400', 'priority': '1', 'channels': '40'}}
{'33': {'xx': '500', 'priority': '2', 'channels': '30'}}

РЕДАКТИРОВАТЬ:

Вот более общий подход, который также меняет формат

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '4', 'channels': '35'}},
      {'11': {'xx': '260', 'priority': '9', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '11', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

filter_dict = [{'11': 2}, {'33': 2}]

res = []
middle_dict = {}
position = 0
first = True

def sortSecond(val): 
    return val[0]

for dd_one_dict in dd:
    for dict_id, sub_dict in dd_one_dict.items():
        if middle_dict.get(dict_id,False):
            middle_dict[dict_id].append((int(sub_dict['priority']),position))
        else:
            middle_dict[dict_id] = [(int(sub_dict['priority']),position)]
        position += 1
    middle_dict[dict_id].sort(key = sortSecond)

external_counter = 0 
for one_key in middle_dict.keys():
    internal_counter = 2
    for items in middle_dict[one_key]:
        if first:
            res.append({one_key:[dd[items[1]][one_key]]})
            first = False
        else:
            for filter_one_dic in filter_dict:
                if one_key == list(filter_one_dic.keys())[0]:
                    if internal_counter <= filter_one_dic[list(filter_one_dic.keys())[0]]:
                        res[external_counter][one_key].append(dd[items[1]][one_key])
                        internal_counter += 1
                    else:
                        break
    first = True
    external_counter += 1

print(res) 

Вывод:

[{'11': [{'xx': '259', 'priority': '1', 'channels': '55'}, {'xx': '260', 'priority': '2', 'channels': '35'}]}, {'22': [{'xx': '300', 'priority': '1', 'channels': '40'}]}, {'33': [{'xx': '400', 'priority': '1', 'channels': '40'}, {'xx': '500', 'priority': '2', 'channels': '30'}]}]
1 голос
/ 16 июня 2020

Вы можете использовать defaultdict, чтобы помочь вам с этим

from collections import defaultdict

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '3', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

res_each = defaultdict(list)
filter_dict = [{'11': 2}, {'33': 2}]
filter_map = {list(i.keys())[0]: list(i.values())[0] for i in filter_dict}
for i in dd:
    res_each[list(i.keys())[0]].append(i)
res = []
for i in [sorted(v, key=lambda x: int(list(x.values())[0]['priority']))[:filter_map.get(k, 1)] for k, v in res_each.items()]:
    res.extend(i)
print(res)

Вывод

[{'11': {'xx': '259', 'priority': '1', 'channels': '55'}}, 
{'11':{'xx':'260','priority': '2', 'channels': '35'}}, 
{'22': {'xx': '300', 'priority': '1', 'channels':'40'}}, 
{'33': {'xx': '400', 'priority': '1', 'channels': '40'}}, 
{'33': {'xx': '500', 'priority': '2', 'channels': '30'}}]
1 голос
/ 16 июня 2020

Я предполагаю, что dd вообще не отсортировано. Надеюсь, это поможет.

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '270', 'priority': '3', 'channels': '35'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]
# firstly sorted by key, then sorted by priority
dd = sorted(dd, key=lambda e: (list(e.keys())[0], int(list(e.values())[0]['priority'])))

filter_dict = [{'11': 2}, {'33': 2}]
filter_dict = {k:v for elem in filter_dict for k,v in elem.items()}
res = []
for i in dd:
    key = list(i.keys())[0]
    if key in filter_dict:
        if filter_dict[key] > 0:
            res.append(i)
            filter_dict[key] -= 1
    else:
        res.append(i)
        filter_dict[key] = 0

for i in res:
    print(i)
1 голос
/ 16 июня 2020

Не очень элегантно, но это выполняет свою работу, используя промежуточный словарь.

dd = [{'11': {'xx': '259', 'priority': '1', 'channels': '55'}},
      {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
      {'11': {'xx': '270', 'priority': '3', 'channels': '35'}},
      {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
      {'22': {'xx': '303', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
      {'33': {'xx': '500', 'priority': '2', 'channels': '30'}},
      {'33': {'xx': '606', 'priority': '3', 'channels': '30'}}]

filter_dict = [{'11': 2}, {'33': 2}]

tmp = {k: d[k] for d in filter_dict for k in d}  # {'11': 2, '33': 2}
out = []
for d in dd:
    id = [*d][0]
    if id not in tmp:
        out.append(d)
        tmp[id] = 0
    elif tmp[id]:
        out.append(d)
        tmp[id] -= 1
    else:
        del tmp[id]

print(out)
[{'11': {'xx': '259', 'priority': '1', 'channels': '55'}}, 
 {'11': {'xx': '260', 'priority': '2', 'channels': '35'}},
 {'22': {'xx': '300', 'priority': '1', 'channels': '40'}},
 {'33': {'xx': '400', 'priority': '1', 'channels': '40'}},
 {'33': {'xx': '500', 'priority': '2', 'channels': '30'}}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...