6
$\begingroup$

I want to implement an operation on the following list:

For a given arbitrary length of list $\{a1,a2,a3,a4,a5,a6,a7,a8,\cdots\}$, the task is to find the number of zeros and their position(s). So I want my output to be:

{number of zeros, {position(s) of zero(s)}

For example, $\{0,1,2,-1,0,1,3,0\}$, I want to count $0$; so zero happens twice and the position of zero to be in 1st, 5th, 8th position, i.e., I want my output as $\{3, \{1, 5 ,8\}\}$.

First of all, I know how to count the zeros:

  list1={0,1,2,-1,0,1,3,0};
  Count[list1, x_ /; x == 0]

Then it gives 3 as an output. Maybe I can find the position(s) by using the loop explicitly, but I think there is a simpler way to implement it in Mathematica.

$\endgroup$
1
  • 3
    $\begingroup$ {Length@#, Flatten@#} &@Position[list1 = {0, 1, 2, -1, 0, 1, 3, 0}, 0] $\endgroup$
    – Alan
    Commented May 4, 2023 at 12:08

5 Answers 5

5
$\begingroup$

For integer lists:

{Length @ #, #} & @  Random`Private`PositionsOf[list1, 0]
{3, {1, 5, 8}}

This is much faster than alternatives for long lists with relatively few zeros.

$\endgroup$
8
$\begingroup$
zeros[ll_] := {Length[#], #} &@Flatten@Position[ll, 0]

or

zeros[ll_] := {Count[ll, 0], Flatten@Position[ll, 0]}

enter image description here

$\endgroup$
8
$\begingroup$

Using PositionIndex:

Clear["Global`*"];
list1 = {0, 1, 2, -1, 0, 1, 3, 0};

cpi[k_List, 
  el_] := {Count[#, el], 
    If[MissingQ@PositionIndex[#][el], {}, PositionIndex[#][el]]} &@k

cpi[list1, #] & /@ Range[0, 4]

Other variations:

Through[{Count[0], Flatten@*Position[0]}[list1]]

{Length@#, #} &@PositionIndex[list1][0]

{{3, {1, 5, 8}}, {2, {2, 6}}, {1, {3}}, {1, {7}}, {0, {}}}

$\endgroup$
4
$\begingroup$
list = {0, 1, 2, -1, 0, 1, 3, 0};

Using Query

Join @@@ Query[{Count[0], Position[0]}] @ list

{3, {1, 5, 8}}

Using Comap (new in 14.0)

Join @@@ Comap[{Count[0], Position[0]}] @ list

{3, {1, 5, 8}}

$\endgroup$
3
$\begingroup$
list1 = {0, 1, 2, -1, 0, 1, 3, 0};

Using MapIndexed and the third argument of GroupBy:

GroupBy[MapIndexed[{#2, #1} &, list1, {-1}], 
Last, {Length@#2, Splice /@ #1} & @@ Thread@# &][0]

{3, {1, 5, 8}}

Or using Replace:

Block[{n = 0}, Last@Replace[list1, 
y_ /; y == 0 :> {++n, Flatten@Position[list1, y]}, {-1}]]

{3, {1, 5, 8}}

$\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.