Подтвердить что ты не робот

Эффективный способ удаления пустых списков из списков?

Каков наиболее эффективный способ удаления всех пустых List[] объектов из всех List, которые появляются в выражении на разных уровнях? Пустой List[] должен быть удален только в том случае, если он является элементом другого List.

4b9b3361

Ответ 1

Эндрю и Алексей указывают, что использование expr //. x_List :> DeleteCases[x, {}, Infinity], как и в моем предыдущем ответе, также удалит {} в blah[{f[{}]}], тогда как он должен оставить его нетронутым, так как его голова f, а не List. Решение, благодаря Леониду, состоит в том, чтобы не использовать ReplaceRepeated, но Replace вместо того, чтобы замены выполнялись на всех уровнях от 0 до Infinity:

Replace[expr, x_List :> DeleteCases[x, {}], {0, Infinity}]

Причина, по которой Replace работает, и ReplaceRepeated не видно из этого небольшого примера. Рассмотрим expr = {a, {}, {b, {}}, c[d, {}]}; в своем TreeForm

enter image description here

Replace работает, начиная с самого внутреннего выражения (-ов), т.е. List[b,{}] и c[d,{}], и работает вверх до вершины node. На каждом уровне проверка головы так же проста, как смотреть вверх по node прямо вверху и видеть, соответствует ли она List. Если это так, примените правило и перейдите на уровень, иначе ничего не делайте и не поднимайтесь на уровень. Это приводит к окончательному дереву:

enter image description here

ReplaceRepeated (//.), с другой стороны, работает, начиная с самого верхнего node и пересекая дерево. Предыдущее решение начинается с проверки того, является ли первый node List и если это так, то применяется DeleteCases, и он перемещается вниз по дереву, безжалостно заменяя каждый {}, который он может найти. Обратите внимание, что он не проверяет, соответствуют ли главы внутренних выражений List, поскольку этот обход сделанный DeleteCases, а не ReplaceRepeated. Когда //. перемещается в последующие нижние узлы, заменить его нечего и он быстро выйдет. Это дерево, которое получается с предыдущим решением:

enter image description here

Обратите внимание, что элемент {} внутри c[d, {}] также удален. Это происходит исключительно из-за того, что DeleteCases (с техникой уровня {0,Infinity} перемещается вниз по дереву. Действительно, если первая глава была чем-то отличным от List, она бы пропустила ее и переместилась на следующий уровень, из которых только {} в {b, {}} является совпадением. Для демонстрации с помощью expr2 = f[a, {}, {b, {}}, c[d, {}]] получаем

enter image description here

Обратите внимание, что в текущем решении с Replace мы используем DeleteCases со спецификацией уровня по умолчанию, которая является только первым уровнем. Поэтому он не проверяет и не удаляет пустые списки глубже, чем на первом уровне, что именно то, что нам нужно здесь.

Хотя мы использовали первый node, чтобы объяснить, почему он терпит неудачу, рассуждение верно для каждого node. Леонид более подробно объясняет эти понятия в своей книге