Уведомления

Группа в Telegram: @pythonsu

#1 Июль 17, 2022 02:18:38

rick1177
Зарегистрирован: 2022-07-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

Товарищи, добрый день.
Я получаю сложные структуры, которые могу являть собой разные сочетания вложенных словарей и списков друг в друга. Например, вот такие наборы:

 a={'tr': {'td': [{'attributes': {'width': '7%'}}, {'text': 'eLIBRARY ID:', 'a': {'text': '58061', 'attributes': {'href': 'title_about_new.asp?id=58061'}}, 'attributes': {'width': '43%', 'align': 'left'}}, {'text': 'Язык описания:', 'font': {'text': 'русский', 'attributes': {'color': '#000000'}}, 'attributes': {'width': '48%', 'align': 'right'}}, {'attributes': {'width': '2%'}}], 'attributes': {'valign': 'middle'}}, 'attributes': {'width': '550', 'cellspacing': '0', 'cellpadding': '3', 'border': '0'}}
a= [{'1':1, "2":[{'3':3},{'4':[{'11':11, '12':12, 'attributes':'pf'}, {'attributes':'pf'}]}, {'attributes':'pf'}], '5':5, 'attributes':'pf'}]
a= [{'1':1, "2":[{'3':3},{'4':4}, {'attributes':'pf'}], '5':5, 'attributes':'pf'}]
a={'1':1, "2":[{'3':3},{'4':4}, {'attributes':'pf'}], '5':5, 'attributes':'pf'}
a=[{'3':3},{'4':4}, {'attributes':'pf'}]
a={'3':3, '4':4, 'attributes':'pf'}
a={'3':{'4':4, 'attributes':'pf'},'5':3}
a={'3':{'4':4, 'attributes':'pf'},'5':3, '6':{'attributes':'pf','7':7, '8':{'9':9, 'attributes':'pf', '10':10}}, 'attributes':'pf'}

Поскольку я не могу знать заранее количество уровней вложенности, то, единственный способ, который мне пришёл в голову - рекурсия.
Мне удалось написать функцию, которая делает почти то, что мне нужно:
 def del_element(dict_or_list):
    if isinstance(dict_or_list,list):
        res=[]
        for i in dict_or_list:
            res.extend(del_element(i))
        yield res
    if isinstance(dict_or_list,dict):
        del_key = ('attributes',)
        for key in del_key:
            if key in dict_or_list:
                del dict_or_list[key]
        for k, v in dict_or_list.items():
            if isinstance(v, dict) and (len(v)!=0):
                yield from del_element(v)
            if isinstance(v, list):
                res = []
                for i in v:
                    res.extend(del_element(i))
                for i in range(len(res)):
                    if len(res[i]) == 0:
                        del res[i]
                yield res
        if (len(dict_or_list)!=0):
            yield dict_or_list

В итоге, я получаю объект-генератор, с которым дальше работаю так:
 a = del_element(a)
for b in a: b=b
print(b)

Но вот проблема, не знаю как с этим справиться. После работы функции на примере выражения:
 a= [{'1':1, "2":[{'3':3},{'4':[{'11':11, '12':12, 'attributes':'pf'}, {'attributes':'pf'}]}, {'attributes':'pf'}], '5':5, 'attributes':'pf'}]
я получаю такой вывод:
[[{'3': 3}, , {'4': [{'11': 11, ‘12’: 12}, {}]}], {'1': 1, ‘2’: [{'3': 3}, {'4': [{'11': 11, ‘12’: 12}, {}]}, {}], ‘5’: 5}]

В выводе видно, что есть пустые словари: {}

Подскажите, плиз, как избавиться от них?

Отредактировано rick1177 (Июль 17, 2022 02:19:57)

Офлайн

#2 Июль 17, 2022 21:49:54

xam1816
Зарегистрирован: 2020-05-11
Сообщения: 1308
Репутация: +  112  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

  
a = [{'1': 1,
      "2": [{'3': 3}, {'4': [{'11': 11, '12': 12, 'attributes': 'pf'}, {'attributes': 'pf'}]}, {'attributes': 'pf'}],
      '5': 5, 'attributes': 'pf'}]
def filter_data(data):
    if isinstance(data, list):
        return [val for i in data if (val := filter_data(i))]
    elif isinstance(data, dict):
        return {k: val for k, v in data.items() if k != 'attributes' and (val := filter_data(v))}
    else:
        return data
print(filter_data(a))
вывод
[{'1': 1, '2': [{'3': 3}, {'4': [{'11': 11, '12': 12}]}], '5': 5}]

Офлайн

#3 Июль 17, 2022 22:40:01

rick1177
Зарегистрирован: 2022-07-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

Добрый день.
Можно ли попросить вас пояснить эти строки:

xam1816
 return [val for i in data if (val := filter_data(i))]
xam1816
 return {k: val for k, v in data.items() if k != 'attributes' and (val := filter_data(v))}
В частности, первый раз вижу конструкцию:
xam1816
 val := filter_data(i)

Отредактировано rick1177 (Июль 18, 2022 00:18:19)

Офлайн

#4 Июль 17, 2022 23:42:42

ntram
Зарегистрирован: 2022-06-19
Сообщения: 75
Репутация: +  3  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

VANISHED

Отредактировано ntram (Окт. 13, 2022 15:54:50)

Офлайн

#5 Июль 18, 2022 00:19:14

xam1816
Зарегистрирован: 2020-05-11
Сообщения: 1308
Репутация: +  112  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

rick1177
В частности, первый раз вижу конструкцию:
val := filter_data(i)
без нее можно написать вот так
  
[filter_data(i) for i in data if filter_data(i)]
но так приходится два раза задействовать функцию, поэтому ввели оператор := для таких случаев

а вообще гуглите вложенные списки, генераторы, итераторы, и тд и тп.

Офлайн

#6 Июль 21, 2022 14:41:04

rick1177
Зарегистрирован: 2022-07-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

xam1816
без нее можно написать вот так:
 [filter_data(i) for i in data if filter_data(i)]

А как бы тогда выглядела эта строка? (что-то туплю)
xam1816
 return {k: val for k, v in data.items() if k != 'attributes' and (val := filter_data(v))}

Отредактировано rick1177 (Июль 21, 2022 14:42:54)

Офлайн

#7 Июль 22, 2022 00:12:01

rick1177
Зарегистрирован: 2022-07-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Сложная рекурсия по списку словарей списков

xam1816
без нее можно написать вот так
Попытался сделать самостоятельно, но что-то не получается:
 def filter_data_2(data):
    if isinstance(data, list):
        return [filter_data(i) for i in data if filter_data(i)]
    elif isinstance(data, dict):
        return {k: filter_data(v) for k, v in data.items() if k != 'attributes' and (filter_data(v))}
    else:
        return data

Результат сильно плохой:
 tr
{'1': 1, '2': [{'3': 3}, {'4': [{'11': 11, '12': 12}]}], '5': 5}
{'1': 1, '2': [{'3': 3}, {'4': 4}], '5': 5}
5
{'4': 4}
4
5
6

Я видимо совсем не понял этой конструкции:
 return {k: val for k, v in data.items() if k != 'attributes' and (val := filter_data(v))}

Что такое двоеточие после k, что здесь происходит?

Отредактировано rick1177 (Июль 22, 2022 00:12:50)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version