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$
1
  • $\begingroup$ Do you want to do like this. Cases[ {{{1, 2}, {3}, {4, 5}}, {{6}, {}}, {{}, {}}}, Except[{{}, {}}]] $\endgroup$
    – Junho Lee
    Commented Aug 28, 2014 at 0:31

5 Answers 5

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$
7
  • $\begingroup$ Oh, wow! I didn't realize the solution would be that simple. Thank you very much. $\endgroup$ Commented Aug 28, 2014 at 0:25
  • $\begingroup$ @Shredderroy, my pleasure. $\endgroup$
    – kglr
    Commented Aug 28, 2014 at 0:35
  • $\begingroup$ @kguler so good ... $\endgroup$
    – eldo
    Commented Aug 28, 2014 at 0:48
  • 3
    $\begingroup$ Cases[list, {___, {__}, ___}] seems simpler and faster. $\endgroup$
    – Michael E2
    Commented Aug 28, 2014 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
    Commented Aug 28, 2014 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$
2
  • $\begingroup$ nice. May be you explain a little for us newbies how this works :) $\endgroup$
    – Nasser
    Commented Aug 28, 2014 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
    Commented Aug 28, 2014 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$
2
  • $\begingroup$ I don't think it will work for all levels. check this: {{{1, 2}, {3}, {4, 5, {5}}}, {{6}, {}, {}}, {{}, {{}, {}}}, {{}, {}, {2}}}; $\endgroup$ Commented Aug 28, 2014 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
    Commented Aug 28, 2014 at 6:07
4
$\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 and acknowledge you have read our privacy policy.

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