7
$\begingroup$

I would like to turn a list which looks like this one:

{{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 3, 4}}

into one which looks like that one:

{{}, {2, 3}, {2}, {2, 3, 4}}

Is there an efficient way to do this?

$\endgroup$
1
  • $\begingroup$ list /. -1 -> Nothing $\endgroup$
    – garej
    Apr 6 '16 at 19:55
14
$\begingroup$

This :

data = {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 3, 4}};
DeleteCases[data, -1, Infinity]

Addressing @Sjoerd's comment, if the list is 2 dimensional one can adjust the level to 2.

data2 = {{-1, -1, -1}, {-1, 2, 3, Exp[-1]}, {-1, -1, 2}, {2, 3, 4}};
DeleteCases[data2, -1, 2]
(* {{}, {2, 3, 1/E}, {2}, {2, 3, 4}} *)
$\endgroup$
3
  • $\begingroup$ Goes wrong if the data contains elements such as Exp[-1]. Only @Mr.Wizard's solution works there. $\endgroup$ Dec 16 '12 at 13:33
  • $\begingroup$ @SjoerdC.deVries Good point, thanks, would my edit fix this ? $\endgroup$ Dec 16 '12 at 13:42
  • $\begingroup$ It does for two dimensional lists, and it looks like the OP is assuming that. $\endgroup$ Dec 16 '12 at 14:15
13
$\begingroup$

Replacing -1 with an empty Sequence should do it:

lst = {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 3, 4}};

(* In *)
lst /. {-1 -> Sequence[]}
(* Out *)
{{}, {2, 3}, {2}, {2, 3, 4}}

If there are expressions containing -1 that shouldn't be replaced, and your list is always of depth 2, you can use Replace instead of ReplaceAll:

lst = {{Exp[-1], -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 3, 4}};

Replace[lst, {-1 -> Sequence[]}, {2}]

Comparing this solution with the DeleteCases solution from b.gatessucks, it seems the DeleteCases solution is faster:

AbsoluteTiming[Do[lst /. {-1 -> Sequence[]}, {100000}]] // First
(* Out *)
0.763795

AbsoluteTiming[Do[DeleteCases[lst, -1, Infinity], {100000}]] // First
(* Out *)
0.448700

Some other alternatives based on the answer by yulinlinyu (and comments):

AbsoluteTiming[Do[Select[#, FreeQ[#, -1] &] & /@ lst, {100000}]] // First
(* Out *)
2.153360

AbsoluteTiming[Do[Cases[#, Except[-1]] & /@ lst, {100000}]] // First
(* Out *)
1.045021

If the actual lst is larger, the tests may come out differently, but I would suspect not.

$\endgroup$
3
  • $\begingroup$ It is really fast! $\endgroup$
    – yulinlinyu
    Dec 12 '12 at 11:29
  • 1
    $\begingroup$ Goes wrong if the data contains elements such as Exp[-1]. Only Mr.Wizard's solution works there. $\endgroup$ Dec 16 '12 at 13:33
  • $\begingroup$ @SjoerdC.deVries: You are right. I added an alternative way using Replace covering this. $\endgroup$
    – Malte Lenz
    Dec 17 '12 at 10:04
2
$\begingroup$

If your (ragged) array is entirely numeric, and your desired operation is to remove all negative values, you could use this:

Pick[#, UnitStep@#, 1] & @ {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 3, 4}}
{{}, {2, 3}, {2}, {2, 3, 4}}

This should prove competitively fast as well.

$\endgroup$
1
$\begingroup$

How about this?

Select[#, Positive] & /@ {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 
   3, 4}}

Edit 1:

 According to Lenz's and Kguler's advice, the code can be

Select[#, FreeQ[#,-1]&] & /@ {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 
       3, 4}}

Or

    Select[#, #!=-1&] & /@ {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 
   2}, {2, 3, 4}}

Edit 2:

 According to the op's comment below, the codes can be something like this:

 Select[#, FreeQ[#,-1]&] & /@ {{-1, -1, -1}, {-1, 2, 3}, {-1, -1, 2}, {2, 
           3, 4}}/.{}->{0,0}
$\endgroup$
4
  • $\begingroup$ This would also remove elements of other negative numbers, which the title of the question indicates is not the wanted scenario. $\endgroup$
    – Malte Lenz
    Dec 12 '12 at 10:10
  • $\begingroup$ thank you for the nice answers. If the result of a sublist is {} it should be turned into {0,0}. How can I do this? $\endgroup$
    – RMMA
    Dec 12 '12 at 10:14
  • $\begingroup$ You could add this as a requirement to the original question. Replacing empty lists with ReplaceAll should be a good way though. $\endgroup$
    – Malte Lenz
    Dec 12 '12 at 10:17
  • 2
    $\begingroup$ maybe FreeQ[#, -1] & instead of Positive? $\endgroup$
    – kglr
    Dec 12 '12 at 10:18
1
$\begingroup$

Translation of python.

Table[If[j != -1, j, ## &[]], {i, list}, {j, i}]
 [[j for j in i if j != -1] for i in list]

A recursive version:

foo[L_] := Table[If[ListQ[i], foo[i], If[i != -1, i, ## &[]]], {i, L}];
foo[list]
$\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.