4

I have some processed data, which are basically a collection of ordered pairs in the form:

{{x1, y1}, {x2, y2}, ..., {xn, yn}}

Ordered pairs which have either a zero $x$ or $y$ component are not physically meaningful, and should be deleted from the data. I can't for the life of me figure out how to delete these points. I've tried DeleteCases, Position, Select, Cases, etc. and none of them work for my application.

István Zachar
  • 47,032
  • 20
  • 143
  • 291
Y. Jones
  • 41
  • 1
  • 3

6 Answers6

5

The best choice is an appropriate use of DeleteCases. I'd recommend DeleteCases with a pattern {___, 0,___} (see BlankNullSequence) since it can remove zeros in more general lists than of those of length 2, moreover it is resonably faster than {a_, 0} | {0, a_}, on the other hand it is slower than {_, 0} | { 0, _}. One can use also {___, 0 | 0., ___} in any case. Let's demonstrate two cases :

list1 = RandomInteger[{-5, 5}, {10^5, 2}];
list3 = RandomInteger[{-5, 5}, {10^6, 2}];


DeleteCases[list3, {a_, 0} | {0, a_}]; // AbsoluteTiming // First
DeleteCases[list3, {_, 0} | {0, _}]; // AbsoluteTiming // First
DeleteCases[list3, {___, 0, ___}]; // AbsoluteTiming // First
0.203125
0.156250
0.171875
DeleteCases[list3, {a_, 0} | {0, a_}]; // AbsoluteTiming // First
DeleteCases[list3, {_, 0} | {0, _}]; // AbsoluteTiming // First
DeleteCases[list3, {___, 0, ___}]; // AbsoluteTiming // First
2.000000
1.609375
1.765625
Artes
  • 57,212
  • 12
  • 157
  • 245
  • Well, not really. The fastest seems to be DeleteCases[list, {_, 0} | {0, _}]. – xzczd Apr 08 '13 at 06:46
  • Where are your tests ? Have you done them ? I've tried more lists and {___, 0, ___} has been faster than {a_, 0} | {0, a_} everytime. – Artes Apr 08 '13 at 06:49
  • ok, I added another case {_, 0} | { 0, _} but one can delete 0 in much longer lists with {___, 0, ___} – Artes Apr 08 '13 at 07:01
  • I've added a snapshot to my answer. It seems that {_, 0} | {0, _} and {a_, 0} | {0, a_} are different… – xzczd Apr 08 '13 at 07:01
5

Don't forget to handle exact and numeric 0 too! The pattern matcher in any case where the zero is specified as the integer 0 (like in Select[list, FreeQ[#, 0] &]) won't recognize a numerical zero, as 0 =!= 0.0.

list = {{1, 1}, {2, 0.}, {0, 4}, {0, 0.}, {2, 2}, {3, 4}, {1, 0.}, {0, 3}};

list /. {___, 0 | 0., ___} :> Sequence[]
{{1, 1}, {2, 2}, {3, 4}}

For even more robustness:

list /. {___, _?PossibleZeroQ, ___} :> Sequence[]

or for testing numerical value (possible other than zero), use Equal explicitly:

list /. {___, _?(# == 0. &), ___} :> Sequence[]

This is necessary as matching with Replace uses MatchQ which tests pattern identity and therefore misses equal numerical values:

0. /. {0 -> True, 0. -> False}                       (* ==> False *)
{MatchQ[0., 0], MatchQ[0.0000000000000000000, 0.]}   (* ==> {False, False} *)
{SameQ[0., 0], SameQ[0.0000000000000000000, 0.]}     (* ==> {False, True} *)
{Equal[0., 0], Equal[0.0000000000000000000, 0.]}     (* ==> {True, True} *)
{PossibleZeroQ@0, PossibleZeroQ@0., PossibleZeroQ@0.0000000000000000000}
                                                     (* ==> {True, True, True} *)
István Zachar
  • 47,032
  • 20
  • 143
  • 291
  • OK, I forgot it completly ORZ… – xzczd Apr 08 '13 at 06:54
  • I actually remembered this after I posted my answer but was too lazy to incorporate it. Nice one. – RunnyKine Apr 08 '13 at 06:58
  • 1
    For robustness you should be using Equal. Some values that you would want to match do not: MatchQ[0.0000000000000000000, 0 | 0.]. – Mr.Wizard Apr 08 '13 at 10:29
  • @Mr.W True that, thanks. – István Zachar Apr 08 '13 at 10:54
  • @Mr.W Please see edit. I wonder why MatchQ[0.0000000000000000000, 0.] does not fall back to use SameQ. What exactly MatchQ uses if it is not SameQ in such cases? – István Zachar Apr 08 '13 at 11:21
  • Perhaps surprisingly SameQ makes slight adjustments for bit rounding. You can set the threshold with Internal`$SameQTolerance. Pattern matching (Replace, Cases, etc) does not actually use SameQ. Incidentally, I find x_ /; x == 0 cleaner than _?(# == 0. &). – Mr.Wizard Apr 08 '13 at 12:55
  • @Mr.Wizard Just a sidenote: I'm not sure Equal is the best case for zero-testing, as it does not return a boolean for nonnumeric input. Therefore Equal could pose a problem when e.g. picking out nontrivial solutions of Solve, e.g. Cases[{x -> 0, x -> k - h/r}, _?(Last@# != 0 &)] vs. Cases[{x -> 0, x -> k - h/r}, _?(Not@PossibleZeroQ@Last@# &)]. – István Zachar Apr 09 '13 at 13:08
  • @István I'm well aware of that behavior, but it's only a problem in inverted cases like you show. You could add TrueQ or write: DeleteCases[{x -> 0, x -> k - h/r}, _?(Last@# == 0 &)]. Of course PossibleZeroQ, SameQ etc. all have a place as well. It really depends on the behavior you want. I'll stand by my statement that Equal is usually the the best choice. – Mr.Wizard Apr 09 '13 at 15:31
  • For readability, I prefer list /. {___, x_ /; x == 0, ___} :> Sequence[]. – J. M.'s missing motivation Apr 22 '13 at 12:51
3

DeleteCases, Position, Select, Cases all works:

list = {{1, 1}, {2, 0}, {0, 4}, {0, 0}};

DeleteCases[list, {a_, 0} | {0, a_}]
Extract[list, Position[list2, {a_ /; a != 0, b_ /; b != 0}]]
Select[list, #[[1]] != 0 && #[[2]] != 0 &]
Select[list, FreeQ[#, 0] &]
Select[list, ! MemberQ[#, 0] &]
Cases[list, Except[{_, 0} | {0, _}]]


(*
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
*)

Here's a speed test for the solutions given by RunnyKine, Artes and me:

enter image description here


OK, I had been completely forgot the 0. before István Zachar mentioned it ORZ. For completeness:

list2 = {{1, 1}, {2, 0}, {0, 4}, {0, 0}, {0, 0.}, {0., 3}, {4, 0.}};

DeleteCases[list2, {a_, 0 | 0.} | {0 | 0., a_}]
Extract[list2, Position[list2, {a_ /; a != 0, b_ /; b != 0}]]
Select[list2, #[[1]] != 0 && #[[2]] != 0 &]
Select[list2, FreeQ[#, 0 | 0.] &]
Select[list2, ! MemberQ[#, 0 | 0.] &]
Cases[list2, Except[{_, 0 | 0.} | {0 | 0., _}]]

(*
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
{{1,1}}
*)

Notice that the modification of the code is only necessary for the pattern match, so my second and third solutions with Unequal(!=) are not changed.

xzczd
  • 65,995
  • 9
  • 163
  • 468
3

This is not general, but because you are removing zeros, you can use tricks like this:

Pick[list, Unitize[Times @@ Transpose @ list], 1]
Simon Woods
  • 84,945
  • 8
  • 175
  • 324
2

Another way, @xzczd covered most of them.

list = {{1, 1}, {2, 0}, {0, 4}, {0, 0}, {2, 2}, {3, 4}, {1, 0}, {0, 3}};

list /. {x_, 0} -> Sequence[] /. {0, y_} -> Sequence[]

OR you could just do

list /. ({x_, 0} | {0, y_}) -> Sequence[]

AND for completeness as suggested by @Istvan

list /. ({x_, 0 | 0.} | {0 | 0., y_}) -> Sequence[]

gives:

{{1, 1}, {2, 2}, {3, 4}}
RunnyKine
  • 33,088
  • 3
  • 109
  • 176
-1

list = {A,B,C,D,E,F}. Using DeleteCases[list, A|C|E] returns {B,D,F}. Also note that "0" is not the same as "0."

David
  • 1