0
$\begingroup$

I wish to group semiprimes into groups with same parity. Mathematica does this well with

SplitBy[ Select[ Range@ 100, PrimeOmega@# == 2 &], Mod[#, 2] &]

So now I want to group semiprimes into groups with alternating parity. Why shouldn't just changing the above code to prefixing the Mod function with ! do the trick?

$\endgroup$
2
  • $\begingroup$ You mean the Not operator? That takes true/false values, not numbers. $\endgroup$
    – Szabolcs
    Commented Apr 22, 2018 at 17:34
  • 3
    $\begingroup$ I don't understand what you mean by "groups with alternating parity". Can you give an example? $\endgroup$ Commented Apr 22, 2018 at 20:45

1 Answer 1

1
$\begingroup$

I understand that you want to start a new group when a parity repeats itself. SplitBy does not seem to compare adjacent list elements, instead it just applies its second argument to every list element. Let's try to work around this.

semiprimes = Select[Range@100, PrimeOmega@# == 2 &]
{4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51,
 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95}
mask = ((-1)^Range@Length@semiprimes + 1)/2
{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}
SplitBy[semiprimes + mask, Mod[#, 2] &] // # - Internal`PartitionRagged[mask, Length /@ #] &
{{4}, {6, 9, 10}, {14, 15}, {21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49},
 {51}, {55}, {57, 58}, {62, 65}, {69, 74, 77, 82, 85, 86, 87}, {91}, {93, 94, 95}}

There is another, very easy way to do this too:

i = 0;
SplitBy[semiprimes, Mod[# + i++, 2] &]

Introducing a counter that changes the parity with every test might be easier, than doing all the above manipulations.

Even though your question is an XY problem, I'll try to explain, why your suggested solution cannot work. Using Mod[#, 2] & in SplitBy internally generates the list

{0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,
 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}

which is then split into runs of consecutive elements.

Using !Mod[#, 2]& gives

{! 0, ! 0, ! 1, ! 0, ! 0, ! 1, ! 1, ! 0, ! 1, ! 0, ! 1, ! 0, ! 1,
 ! 0, ! 1, ! 0, ! 1, ! 1, ! 1, ! 1, ! 0, ! 0, ! 1, ! 1, ! 0, ! 1,
 ! 0, ! 1, ! 0, ! 1, ! 1, ! 1, ! 0, ! 1}

which is again the same combination of runs of identical elements. And even if applying Not would have worked as you had presumably intended, you would get something like

{1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1,
 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0}

which gives the same sequence of runs of identical elements.

Thus, your function must have some memory of the previous element to get runs of alternating parity, which is what I have done by introducing the variable i in my second solution.

$\endgroup$

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