11
$\begingroup$

I want to delete the complete list within a list containing 0 at any position.

I tried using:

DeleteCases[Tuples[Range[-2, 2], 2], {0 ..}]

{{-2, -2}, {-2, -1}, {-2, 0}, {-2, 1}, {-2, 2}, {-1, -2}, {-1, -1}, {-1, 0}, {-1, 1}, {-1, 2}, {0, -2}, {0, -1}, {0, 1}, {0, 2}, {1, -2}, {1, -1}, {1, 0}, {1, 1}, {1, 2}, {2, -2}, {2, -1}, {2, 0}, {2, 1}, {2, 2}}

But only the lists starting with 0 are removed.

How can I remove the entire list that contains 0 at any place?

$\endgroup$

7 Answers 7

9
$\begingroup$
 DeleteCases[Tuples[Range[-2, 2], 2], {___, 0, ___}] (* or *)
 DeleteCases[data, {0, 0}|{1,0}|{0,1}]

{{-2, -2}, {-2, -1}, {-2, 1}, {-2, 2}, {-1, -2}, {-1, -1}, {-1, 1}, {-1, 2}, {1, -2}, {1, -1}, {1, 1}, {1, 2}, {2, -2}, {2, -1}, {2, 1}, {2, 2}}

Alternatively, if you can, remove zeros from the input lists before using Tuples:

Tuples[Join[-Reverse@#, #]&@Range[2],2]

same result

Even if data = Tuples[Range[-2, 2], 2] is already created, processing data to create a zero-free input list and using Tuples on it is (to my surprise) faster than using Pick to remove entries with zeros from pairs of data:

data = Tuples[Range[-100, 100], 2];

ra = Tuples[Join[-Reverse @ #, #]& @ Range[100],2]; // RepeatedTiming // First

0.0000524

rb = With[{r = DeleteCases[DeleteDuplicates @ Flatten[data], 0]},
  Tuples[r, 2]];// RepeatedTiming // First  

0.000178

rc = Pick[data, Unitize[data].{1, 1}, 2];//RepeatedTiming//First (*from @Henrik's answer*)

0.0013

rd = DeleteCases[data, {0, 0}|{1,0}|{0,1}];// RepeatedTiming // First  

0.017

re = DeleteCases[data, {___, 0, ___}];// RepeatedTiming // First   

0.026

rf = Select[data, FreeQ[0] ];// RepeatedTiming // First  (*from David's answer *)

0.060

ra == rb == rc == rd == re == rf

True

$\endgroup$
5
  • $\begingroup$ Well.... if you're free to delete 0 before using Tuples simply use Tuples[{-2, -1, 1, 2}, 2]. $\endgroup$ Sep 12, 2018 at 20:15
  • $\begingroup$ @David, yes; i used the more cumbersome way to deal with cases like Range[-100, 100] $\endgroup$
    – kglr
    Sep 12, 2018 at 20:27
  • 1
    $\begingroup$ Oh, method b and c... nice out-of-the-box-thinking! $\endgroup$ Sep 12, 2018 at 21:42
  • $\begingroup$ DeleteCases[DeleteDuplicates @ Flatten[data], 0] is not packed, while Join[-Reverse @ #, #]& @ Range[100] is, explaining the difference in timing $\endgroup$
    – Carl Woll
    Sep 12, 2018 at 23:39
  • $\begingroup$ @CarlWoll, good point. But in this case, DeleteDuplicates @ Flatten[data] (which is packed) already takes 0.00011 seconds (RepeatedTiming) compared to 3.06*10^-6 for Join[-Reverse @ #, #]& @ Range[100], simply because the former processes a list with dimensions {40401,2} and the latter with just {200}. $\endgroup$
    – kglr
    Sep 13, 2018 at 0:28
8
$\begingroup$

Here a more cumbersome (not a code golfer) but faster approach:

data = Tuples[Range[-100, 100], 2];
a = DeleteCases[data, {___, 0, ___}]; // RepeatedTiming // First
b = Pick[data, Unitize[data].{1, 1}, 2]; // RepeatedTiming // First
a == b

0.028

0.00098

True

This skips pattern matching in favor of faster vectorized functions.

$\endgroup$
8
$\begingroup$

Or...

Select[Tuples[Range[-2, 2], 2], ! MemberQ[#, 0] &]

or as @ThatGravityGuy points out...

Select[Tuples[Range[-2, 2], 2], FreeQ[#, 0] &]
$\endgroup$
4
  • 1
    $\begingroup$ Instead of !MemberQ couldn't you just use FreeQ? $\endgroup$ Sep 12, 2018 at 19:45
  • $\begingroup$ Oooh... of course. Yes. Thanks. $\endgroup$ Sep 12, 2018 at 19:47
  • $\begingroup$ You can use the operator form FreeQ[0] instead of FreeQ[#, 0] & $\endgroup$
    – kglr
    Sep 12, 2018 at 21:36
  • 1
    $\begingroup$ .. or operator forms of both Select and FreeQ: Select[FreeQ@0]@data $\endgroup$
    – kglr
    Sep 12, 2018 at 23:17
2
$\begingroup$
list = Tuples[Range[-2, 2], 2];

Using SequenceSplit (new in 11.3) with OrderlessPatternSequence

Join @@ SequenceSplit[list, {{OrderlessPatternSequence[0, _]}}]

{{-2, -2}, {-2, -1}, {-2, 1}, {-2, 2}, {-1, -2}, {-1, -1}, {-1, 1}, {-1, 2}, {1, -2}, {1, -1}, {1, 1}, {1, 2}, {2, -2}, {2, -1}, {2, 1}, {2, 2}}

With long lists SequenceSplit gets very slow

$\endgroup$
1
$\begingroup$
Pick[#,Unitize[MapApply[Times]@#],1]&[Tuples[Range[-2, 2], 2]]


(* 
   {{-2,-2},{-2,-1},{-2,1},{-2,2},{-1,-2},{-1,-1},{-1,1},{-1,2},{1,-2},
    {1,-1},{1,1},{1,2},{2,-2},{2,-1},{2,1},{2,2}} 
*)
$\endgroup$
1
$\begingroup$

Remove all the entries with product of the elements zero:

Complement[list, Extract[list, Position[Times[#[[1]], #[[2]]] & /@ list, 0]]]
$\endgroup$
1
$\begingroup$
list = Tuples[Range[-2, 2], 2]

Using Replace:

Replace[list, x_ /; ! FreeQ[x, 0] :> Nothing, {1}]

(*{{-2, -2}, {-2, -1}, {-2, 1}, {-2, 2}, {-1, -2}, {-1, -1}, {-1, 1}, {-1, 2},
   {1, -2}, {1, -1}, {1, 1}, {1, 2}, {2, -2}, {2, -1}, {2, 1}, {2, 2}}*)

Or using SequenceCases:

Join @@ SequenceCases[list, s : {__} /; FreeQ[s, 0] :> s]

(*{{-2, -2}, {-2, -1}, {-2, 1}, {-2, 2}, {-1, -2}, {-1, -1}, {-1, 1}, {-1, 2},
   {1, -2}, {1, -1}, {1, 1}, {1, 2}, {2, -2}, {2, -1}, {2, 1}, {2, 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.