Sorting a list according to some pre-specified rules
Answer
Depending what you mean one of these has your answer.
This matches your example, requiring any of the two numbers to be Divisible
by 3 in order to sort them.
Sort[
{12, 9, 3, 42, 30, 10, 11, 1, 2}
, If[
Divisible[#1, 3] || Divisible[#2, 3]
, #2 < #1
, 0
] &
]
(* {42, 30, 12, 10, 11, 9, 3, 1, 2} *)
This matches better your original text description, requires both numbers to be Divisible
to sort them. Otherwise they remain in place.
Sort[
{12, 9, 3, 42, 30, 10, 11, 1, 2}
, If[
Divisible[#1, 3] && Divisible[#2, 3]
, #2 < #1
, 0
] &
]
(* {42, 30, 12, 9, 3, 10, 11, 1, 2} *)
Explanation
Sort
allows a second argument to define the ordering function.
The ordering function takes two arguments #1
and #2
to be compared and normally should return either True
or False
. Sort also accepts it to return 0
when two elements should be treated as identical.
So the strategy is to ask first If
the numbers should be sorted using Divisible
, and then return True
or False
if they should be sorted, or 0
otherwise. Number that are not sorted remain in their place.
Update: A more convenient function that takes a criterion and a sort-order as arguments:
ClearAll[f]
f[criterion_, sortorder_: Greater] := sortorder[##] Boole[AnyTrue[{##}, criterion]] &
Examples:
lst = {12, 9, 3, 42, 30, 10, 11, 1, 2};
sorted = {42, 30, 12, 10, 11, 9, 3, 1, 2}; (* desired output from OP *)
Sort[lst, f[Divisible[#, 3] &]] == sorted
True
Sort in increasing order with the same criterion:
Sort[lst, f[Divisible[#, 3]&, Less]]
{3, 9, 10, 11, 1, 2, 12, 30, 42}
Use Divisible[#, 2]&
as the criterion to specify the sublist that should be kept in its original order (those elements of lst
that does not satisfy the criterion):
Sort[lst, f[Divisible[#, 2]&]]
{42, 30, 12, 9, 3, 11, 10, 2, 1}
Original answer:
lst = {12, 9, 3, 42, 30, 10, 11, 1, 2};
sorted = {42, 30, 12, 10, 11, 9, 3, 1, 2}; (* desired output from OP *)
ClearAll[f1]
f1[x_] := Boole[Or @@ Divisible[{##}, x]]Greater[##] &;
Sort[lst, f1 @ 3] == sorted
True
Sort[lst, f1 @ 2]
{42, 30, 12, 9, 3, 11, 10, 2, 1}
This would be how I would think of it
Extract multiples of 3
Sort into decreasing order
Extract non-multiples of 3
Join those two results together
and translate that into Mathematica
v={12,9,3,42,30,10,11,1,2};
mult3[x_]:=Mod[x,3]==0;
notmult3[x_]:=Mod[x,3]!=0;
Join[
Sort[Select[v,mult3],Greater],
Select[v,notmult3]
]
giving
{42, 30, 12, 9, 3, 10, 11, 1, 2}