5
$\begingroup$

I want to eliminate all the sub lists containing exactly two positive numbers? My list is

M = {{-2,4,0,12}, {0,7}, {3,6,9,11}, {2,3,0}, {1,4}, {-3,7,8}, {-2,5}, 
 {-7,-3,0,1,2}, {1,2,3}};

However, going through the Mathematica Tutorial on List Manipulation has garnered me help on how to specify my criteria. Can someone help me please?

$\endgroup$
3
  • 3
    $\begingroup$ Assuming that your List is only ever 3 levels deep, DeleteCases[M, _?(2 == Count[#, _?Positive] &)]] $\endgroup$
    – IPoiler
    Nov 4, 2015 at 2:50
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$
    – Michael E2
    Nov 4, 2015 at 2:50
  • $\begingroup$ You can format inline code and code blocks by selecting the code and clicking the {} button above the edit window. The edit window help button ? is also useful for learning how to format your questions and answers. You may also find this this meta Q&A helpful $\endgroup$
    – Michael E2
    Nov 4, 2015 at 2:51

7 Answers 7

9
$\begingroup$

Select[] + Count[] is a more straightforward approach:

m = {{-2, 4, 0, 12}, {0, 7}, {3, 6, 9, 11}, {2, 3, 0}, {1, 4}, {-3, 7, 8},
     {-2, 5}, {-7, -3, 0, 1, 2}, {1, 2, 3}};

Select[m, Count[#, _?Positive] != 2 &]
   {{0, 7}, {3, 6, 9, 11}, {-2, 5}, {1, 2, 3}}

But if you insist on DeleteCases[]:

DeleteCases[m, v_ /; Count[v, _?Positive] == 2]
$\endgroup$
3
  • $\begingroup$ Maybe is useful to note that this solution removes any sublist that contains al least two positive numbers, so this code removes elements {{-2, 4, 0, 12}, {2, 3, 0}, {1, 4}, {-3, 7, 8}, {-7, -3, 0, 1, 2}} from the main list (if I understood well user35305 asked to remove sublist formed by exactly two positive numbers, i.e. just the element {1, 4}) $\endgroup$
    – Guido
    Nov 4, 2015 at 14:46
  • $\begingroup$ @Guido, OP said "exactly two", not "only two". If the latter was in fact intended, then you're right. (The OP did forget to mention the expected output, so...) $\endgroup$ Nov 4, 2015 at 15:14
  • $\begingroup$ @JM thank you. In fact because of my not-so-good English, I was not sure to have understood correctly what was the question's expected output. $\endgroup$
    – Guido
    Nov 4, 2015 at 15:47
7
$\begingroup$

If you meant to delete cases where there is only a pair of positive numbers:

DeleteCases[M, {x_ /; x > 0, y_ /; y > 0}]
$\endgroup$
1
  • 4
    $\begingroup$ Or DeleteCases[M, {_?Positive, _?Positive}] $\endgroup$
    – Bob Hanlon
    Nov 4, 2015 at 4:02
2
$\begingroup$

To select sublists with exactly two positive numbers using a point-free style:

m = {{-2, 4, 0, 12}, {0, 7}, {3, 6, 9, 11}, {2, 3, 0}, {1, 4}, {-3, 7,
    8}, {-2, 5}, {-7, -3, 0, 1, 2}, {1, 2, 3}};

Select[EqualTo[2]@*Count[1]@*Sign][m]

Pick[m, Map[EqualTo[2]@*Count[1]@*Sign, m]]

{{-2, 4, 0, 12}, {2, 3, 0}, {1, 4}, {-3, 7, 8}, {-7, -3, 0, 1, 2}}


To delete sublists with exactly two positive numbers, use the following:

Select[Not@*EqualTo[2]@*Count[1]@*Sign][m]

Pick[m, Map[Not@*EqualTo[2]@*Count[1]@*Sign, m]]

Pick[m, Map[EqualTo[2]@*Count[1]@*Sign, m], False]

{{0, 7}, {3, 6, 9, 11}, {-2, 5}, {1, 2, 3}}

$\endgroup$
2
$\begingroup$
list = 
 {{-2, 4, 0, 12}, {0, 7}, {3, 6, 9, 11}, {2, 3, 0}, {1, 4}, 
  {-3, 7, 8}, {-2, 5}, {-7, -3, 0, 1, 2}, {1, 2, 3}};

Using Replace and Nothing

Replace[list, x_ /; Count[x, _?Positive] == 2 :> Nothing, {1}]

{{0, 7}, {3, 6, 9, 11}, {-2, 5}, {1, 2, 3}}

$\endgroup$
1
$\begingroup$

Just some variants using Pick and Reap, Sow (have voted for other answers):

Pick[m, Total@# == 2 & /@ Map[Boole[# > 0] &, m, {2}], False]
bc[n_] := BooleanCountingFunction[{2}, Length[n]] @@ (# > 0 & /@ n);
Pick[m, bc /@ m, False]
Pick[m, Count[#, _?Positive] == 2 & /@ m, False]
Reap[Sow[#, bc@#] & /@ m, False, #2 &][[-1, 1]]
$\endgroup$
2
  • $\begingroup$ why not use UnitStep or friends in the first solution? $\endgroup$
    – Wjx
    Aug 24, 2016 at 11:57
  • $\begingroup$ @Wjx very good suggestion. Feel free to edit (with attribution of course)...was just in a mood :) $\endgroup$
    – ubpdqn
    Aug 24, 2016 at 11:59
1
$\begingroup$

A simple modification of ubpdqn's answer, it seems that it will be slightly faster:

Pick[m,Total/@(1-UnitStep[-m]),Except@2]

I will always think of UnitStep, UnitBox, Sign and friends when dealing with these problems involving simple selection criteria as they'll be quite fast and easy to manipulate.

$\endgroup$
1
$\begingroup$
m = {{-2, 4, 0, 12}, {0, 7}, {3, 6, 9, 11}, {2, 3, 0}, {1, 4},
     {-3, 7, 8}, {-2, 5}, {-7, -3, 0, 1, 2}, {1, 2, 3}};

Using ReplaceAll and CountsBy:

m /. v_?VectorQ /; (CountsBy[v, # > 0 &][True] == 2) :> Nothing

(*{{0, 7}, {3, 6, 9, 11}, {-2, 5}, {1, 2, 3}}*)

Or using GroupBy:

Catenate@KeySelect[GroupBy[m, Count[#, _?Positive] &], # != 2 &]

(*{{0, 7}, {-2, 5}, {3, 6, 9, 11}, {1, 2, 3}}*)

Or a slot-free variation (Thanks to @eldo!):

Catenate@KeySelect[FreeQ@2]@GroupBy[m, Count@_?Positive]
$\endgroup$
2
  • 1
    $\begingroup$ Very nice - A slot-free variation: Catenate@KeySelect[FreeQ@2]@GroupBy[m, Count@_?Positive] $\endgroup$
    – eldo
    Jan 23 at 20:12
  • $\begingroup$ Very nice slot-free variation, @eldo! :-) $\endgroup$ Jan 23 at 20:15

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.