Delete efficiently rows of empty list elements inside a list

Here is a very simple and concise construct for doing what you ask.

a = 
  {{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}, 
   {{}, {}, {}}, 
   {{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}};
a //. {} -> Nothing
{{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}, 
 {{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}}

It has the advantage of working for { } appearing at any level.

b = 
  {{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}, 
   {{}, {}, {}}, 
   {{}, {{{}, {{}}, {}}}, {}}};
b //. {} -> Nothing
{{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}}

Note that I used the very useful new symbol Nothing. This means the above solution only works for V10.2 or later.


For arbitrarily nested lists one could also use MapAll and the operator form of DeleteCases:

b = (* m_goldberg's example *)
  {{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}, 
   {{}, {}, {}}, 
   {{}, {{{}, {{}}, {}}}, {}}};

DeleteCases[{}] //@ b
{{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}}

It works via the bottom-up standard evaluation order.

This however is somewhat slower than //. in a single test. Using an anonymous function instead of the operator form is a little faster than //. however in the same test, though less clean:

DeleteCases[#, {}] & //@ b
{{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}}

I don't have the same interpretation of OP requirements as others seem to, but here's my take on those interpretations:

DeleteCases[#, Nest[{# ...} &, {}, Depth[#]], Infinity] &@b

Where b is of course the target list.

Unless Nothing performs much faster than the use of Sequence[], this seems to do quite well against what appears to be the fastest "get rid of any empty list anywhere" solution.

Edit: I used this to generate test b:

b = 
 RandomChoice[
  {9, 1, 1, 1, 9} -> 
   {{{1, 2, 3}, {0, 0, 0}, {4, 5, 6}}, 
    {{}, {}, {}}, {{}, {{{}, {{}}, {}}}, {}}, {{}}, 
    {{1, 2, 3}, {}, {{{{{{{{{{{{1, 2, 3, {{{}, {1, 2, 3}}}}}}}}}}}}}}},
     {1,2, 3, {}}}}, 1000000];