6
$\begingroup$

I have a problem that, admittedly, I have already solved using Select instead, but it is irking me that I cannot seem to construct the right pattern to solve it using Cases. I would like the output of

Cases[
    {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}},
    (* THE CORRECT PATTERN HERE *)
]

to be

{{{1, 2}, {3}, {4, 5}}, {{6}, {}}}

In other words, I would like a pattern that picks up all the elements of the outer list that have at least one non-empty list as an element.

Thanks in advance for your help.

$\endgroup$
  • $\begingroup$ Do you want to do like this. Cases[ {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}}, Except[{{}, {}}]] $\endgroup$ – Junho Lee Aug 28 '14 at 0:31
8
$\begingroup$
list = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}};
Cases[list, Except[{{} ..}]]
(* {{{1, 2}, {3}, {4, 5}}, {{6}, {}}} *)

or

Cases[list, {___, Except[{}], ___}]
(* {{{1, 2}, {3}, {4, 5}}, {{6}, {}}} *)

You can also use PatternTest (_?func) where func is any selector function that you might have used as the second argument of Select. For example:

Select[list, Union @@ # =!= {} &]  (* or Flatten @ # =!= {} & or  ... *)
(* {{{1, 2}, {3}, {4, 5}}, {{6}, {}}}  *)

Cases[list, _?(Union @@ # =!= {} &)]
(*  {{{1, 2}, {3}, {4, 5}}, {{6}, {}}} *)
$\endgroup$
  • $\begingroup$ Oh, wow! I didn't realize the solution would be that simple. Thank you very much. $\endgroup$ – Shredderroy Aug 28 '14 at 0:25
  • $\begingroup$ @Shredderroy, my pleasure. $\endgroup$ – kglr Aug 28 '14 at 0:35
  • $\begingroup$ @kguler so good ... $\endgroup$ – eldo Aug 28 '14 at 0:48
  • 3
    $\begingroup$ Cases[list, {___, {__}, ___}] seems simpler and faster. $\endgroup$ – Michael E2 Aug 28 '14 at 1:29
  • $\begingroup$ @MichaelE2, that is surprising! Makes you think; I wouldn't have expected it to work; now i think i see why it works ... -- which makes pattern puzzles such fun :) I would be happy to add to my answer but I think you should post it as a separate answer. $\endgroup$ – kglr Aug 28 '14 at 2:08
10
$\begingroup$

Here's a way, that is a bit like @kguler's, but it's simpler and a little faster:

list = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}};

Cases[list, {___, {__}, ___}]
(*
  {{{1, 2}, {3}, {4, 5}}, {{6}, {}}}
*)

The pattern ___ (three underscores or BlankNullSequence) matches zero or more things and the pattern __ (two underscores or BlankSequence) matches one or more things. So the pattern {___, {__}, ___} represents a list containing

  1. zero or more things, followed by
  2. a list containing at least one thing, followed by
  3. zero or more of things.

All in all, it matches a list that contains at least one element that is a nonempty list. Cases will match this against the elements of list at level one.

$\endgroup$
  • $\begingroup$ nice. May be you explain a little for us newbies how this works :) $\endgroup$ – Nasser Aug 28 '14 at 2:15
  • $\begingroup$ Michael, this made me realize that i could also use the pattern {___, Except[{}], ___} instead of the earlier contraption {___,{___,Except[{}],___},___}... $\endgroup$ – kglr Aug 28 '14 at 2:40
7
$\begingroup$

Unless you have other requirements I recommend DeleteCases:

list = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}};

DeleteCases[list, {{} ..}]
{{{1, 2}, {3}, {4, 5}}, {{6}, {}}}

For deletion at all levels you could use:

list /. {{} ..} -> Sequence[]
{{{1, 2}, {3}, {4, 5}}, {{6}, {}}}
$\endgroup$
  • $\begingroup$ I don't think it will work for all levels. check this: {{{1, 2}, {3}, {4, 5, {5}}}, {{6}, {}, {}}, {{}, {{}, {}}}, {{}, {}, {2}}}; $\endgroup$ – Algohi Aug 28 '14 at 4:30
  • $\begingroup$ @Algohi It does work on that list but it doesn't remove the new expression {{}} that is created. That is a different interpretation from what I intended. If you with to remove that you could use //. but be aware that it is inefficient. For greater efficiency one might use: Replace[list, {({} | _Sequence) ..} -> Sequence[], {1, -1}] $\endgroup$ – Mr.Wizard Aug 28 '14 at 6:07
3
$\begingroup$

that picks up all the elements of the outer list that have at least one non-empty list as an element.

I think Except is the logical choice and more functional also. But for fun, since Length[] applied to {{}} gives zero (after Flatten), may be this can be used to check

lis = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}};
Cases[lis, x_ /; Length[Flatten@x] > 0]
     (*  {{{1, 2}, {3}, {4, 5}}, {{6}, {}}} *)

Or can do direct compare to {} (after Flatten also)

lis = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}};
Cases[lis, x_ /; Not[SameQ[Flatten@x, {}]]]
   (* {{{1, 2}, {3}, {4, 5}}, {{6}, {}}} *)

another test

lis = {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}, {{}, {}, {2}}};
Cases[lis, x_ /; Not[SameQ[Flatten@x, {}]]]
   (* {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}, {2}}} *)
$\endgroup$
1
$\begingroup$

How a bout this for all levels:

lis = {{{1, 2}, {3}, {4, 
     5, {5}}}, {{6}, {}, {}}, {{}, {{}, {}}}, {{}, {}, {2}}};
    Select[lis , #/# =!= # || # =!= # + # &] // Quiet
      (* {{{1, 2}, {3}, {4, 5, {5}}}, {{6}, {}, {}}, {{}, {}, {2}}} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.