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
    Commented Apr 6, 2016 at 19:55

5 Answers 5

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$ Commented Dec 16, 2012 at 13:33
  • $\begingroup$ @SjoerdC.deVries Good point, thanks, would my edit fix this ? $\endgroup$ Commented Dec 16, 2012 at 13:42
  • $\begingroup$ It does for two dimensional lists, and it looks like the OP is assuming that. $\endgroup$ Commented Dec 16, 2012 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
    Commented Dec 12, 2012 at 11:29
  • 1
    $\begingroup$ Goes wrong if the data contains elements such as Exp[-1]. Only Mr.Wizard's solution works there. $\endgroup$ Commented Dec 16, 2012 at 13:33
  • $\begingroup$ @SjoerdC.deVries: You are right. I added an alternative way using Replace covering this. $\endgroup$
    – Malte Lenz
    Commented Dec 17, 2012 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
    Commented Dec 12, 2012 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
    Commented Dec 12, 2012 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
    Commented Dec 12, 2012 at 10:17
  • 2
    $\begingroup$ maybe FreeQ[#, -1] & instead of Positive? $\endgroup$
    – kglr
    Commented Dec 12, 2012 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 and acknowledge you have read our privacy policy.

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