#python #python-3.x #recursion
#python #python-3.x #рекурсия
Вопрос:
Я пытаюсь создать функцию allsametree(tree)
, которая принимает список, tree
, в качестве входных данных и возвращает TRUE или FALSE, если все элементы списка численно идентичны. Пока у меня есть следующая функция:
def allsametree(tree):
if not type(tree) == list:
return tree
if type(tree) is list:
final_lst = []
for item in tree:
final_lst.append(allsametree(item))
return final_lst[1:] == final_lst[:-1]
Хотя по большей части эта функция работает, она сталкивается с проблемой при оценке allsametree([1, [[[[[2]]]]]])
Какие-либо советы или альтернативные способы решения этой проблемы?
Ответ №1:
Вы можете рекурсивно преобразовать список в набор элементов и вернуть true, если длина всего набора равна 1:
def allsametree(tree):
def to_set(tree):
if isinstance(tree, list):
return {item for obj in tree for item in to_set(obj)}
return {tree}
return len(to_set(tree)) == 1
Комментарии:
1. Хотя это касается случая, указанного выше, меня также беспокоит оценка пустых списков
[]
. Этот метод будет пропускать пустые списки и возвращать false, посколькуlen([])
вместо 1 будет 0. Тем не менее, я ценю вашу помощь.2. OP не указывает, что возвращать с пустым списком, но из формулировки «все элементы идентичны» я интерпретирую это как список, в котором должно быть что-то вообще, чтобы считаться имеющим идентичные элементы. В противном случае его легко изменить
== 1
<= 1
.3. Спасибо за разъяснения, и это, безусловно, имеет смысл!
Ответ №2:
Другой способ сделать это. Разделите его на две операции: сглаживание и проверка того, что все значения одинаковы.
Сглаживание преобразует вложенную итерацию в одну из одного измерения. Так [1, [[[[[2]]]]]]
становится [1,2]
.
Затем прочитайте первое значение и выполните цикл по остальным, чтобы проверить, совпадают ли они с ним.
Вот код
from collections.abc import Iterable
def flatten(iterable):
for i in iterable:
if isinstance(i, Iterable):
yield from flatten(i)
else:
yield i
def allsametree(tree):
flat = flatten(tree)
iterator = iter(flat)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == rest for rest in iterator)
Это будет работать для любых iterable
, а не только для списков, и поскольку он использует отложенную оценку, он остановится, когда найдет два значения, которые не равны. Это избавляет вас от выполнения ненужной работы. Это также позволяет избежать создания временных коллекций (списков, наборов и т. Д.), Создаваемых при каждом рекурсивном вызове.
Вот несколько тестовых входных данных.
Комментарии:
1. Это очень проницательно, я об этом не думал. Спасибо!