Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Andrew and Alexey point out that using <code>expr //. x_List :&gt; DeleteCases[x, {}, Infinity]</code> as I had in my previous answer will also remove the <code>{}</code> in <code>blah[{f[{}]}]</code>, whereas it should leave it untouched as its head is <code>f</code>, not a <code>List</code>. The solution, thanks to Leonid, is to not use <code>ReplaceRepeated</code>, but <code>Replace</code> instead with replacements being made at all levels from <code>0</code> through <code>Infinity</code>:</p> <pre><code>Replace[expr, x_List :&gt; DeleteCases[x, {}], {0, Infinity}] </code></pre> <hr> <p>The reason why <code>Replace</code> works and <code>ReplaceRepeated</code> doesn't can be seen from this little example. Consider <code>expr = {a, {}, {b, {}}, c[d, {}]};</code> in its <code>TreeForm</code></p> <p><img src="https://i.stack.imgur.com/W4qP2.png" alt="enter image description here"></p> <p><code>Replace</code> works by starting with the innermost expression(s) first, i.e., <code>List[b,{}]</code> and <code>c[d,{}]</code>, and works upwards to the top node. At each level, checking the head is as simple as looking up to the node right above and see if it matches <code>List</code>. If it does, apply the rule and move up a level, else do nothing and move up a level. This results in a final tree:</p> <p><img src="https://i.stack.imgur.com/FiGfG.png" alt="enter image description here"></p> <p><code>ReplaceRepeated</code> (<code>//.)</code>, on the other hand, works by starting with the top most node and traversing down the tree. The previous solution starts by checking if the first node is a <code>List</code> and if it is, then <code>DeleteCases</code> is applied and it moves down the tree, ruthlessly replacing every <code>{}</code> it can find. Note that it does not check if the heads of the inner expressions also match <code>List</code>, because this traversal is done by <code>DeleteCases</code>, not <code>ReplaceRepeated</code>. When <code>//.</code> moves to subsequent lower nodes, there is nothing more to replace and it exits quickly. This is the tree that one gets with the previous solution:</p> <p><img src="https://i.stack.imgur.com/d5bkm.png" alt="enter image description here"></p> <p>Note that the <code>{}</code> inside <code>c[d, {}]</code> has also been removed. This is solely due to the fact that <code>DeleteCases</code> (with level specification <code>{0,Infinity}</code> moves down the tree. Indeed, if the first head had been something other than <code>List</code>, it would've skipped it and moved to the next level, of which only the <code>{}</code> in <code>{b, {}}</code> is a match. To demostrate with <code>expr2 = f[a, {}, {b, {}}, c[d, {}]]</code>, we get</p> <p><img src="https://i.stack.imgur.com/JkVJY.png" alt="enter image description here"></p> <p>Note that in the current solution with <code>Replace</code>, we use <code>DeleteCases</code> with the default level specification, which is the first level only. It does not, therefore, check for and delete empty lists deeper than on the first level, which is exactly what we need here.</p> <p>Although we used the first node to explain why it fails, the reasoning holds true for every node. Leonid explains these concepts in greater detail in <a href="http://www.mathprogramming-intro.org/book/node218.html" rel="noreferrer">his book</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload