# Tag Info

13

In general SortBy can do pretty much anything that Sort does; in some cases, possibly better or faster. You can find many comparisons on this site if you just search for both function names. I also disagree with @user21382 that his task could not be expressed elegantly in SortBy form: not only can it be done, I would actually argue that it could be done ...

12

Here's another way you might approach this kind of thing -- instead of assigning values to the variables using =, you can make them into rules. For example, here is a collection of "variable names" and values for those variables, and a rule to make the assignment explicit: vars = {a, b, c, d, e}; vals = {5, 4, 3, 2, 1.1}; Thread[Rule[vars, vals]] {a -> ...

11

I do not believe that this behaviour is a bug. The correct usage would be SortBy[#age&] or SortBy[Key@"age"]. The rest of this response will explain these assertions. The crucial point is that the "age" argument in SortBy["age"] is not conferred with any special meaning on account of SortBy being used as a Dataset operator. In the absence of such ...

10

To sort by a specific element use a pure function with the number in question. For your case (the second element) just do: SortBy[a, #[[2]] &] {{7, 1, 4}, {1, 2, 3}, {12, 4, 8}, {3, 5, 6}, {10, 7, 1}} You can also use Sort like this: Sort[a, #1[[2]] < #2[[2]] &]

9

You have to use a pure function also for SortBy titanic[Select[#age > 65 &] /* SortBy[#age &]] Since #age will pick out the values of the key "age" in the association.

9

I don't know exactly why Mathematica is giving a wrong result, but here's a workaround: SortBy[{{4/13 (-9 - Sqrt[3]), 6/13 (4 - Sqrt[3])}, {4/13 (-9 + Sqrt[3]), 6/13 (4 + Sqrt[3])}}, -N @ #[[2]] &] That is, force Mathematica to sort by their numerical value. OR you can use Sort instead: Sort[{{4/13 (-9 - Sqrt[3]), 6/13 (4 - Sqrt[3])}, ...

9

Unless you use := for varList definition. a,b... are lost. Here's more about that, in related Q&A: Generate list of strings from a list of assigned variables. So: a = 5; b = 4; c = 3; d = 2; e = 1; varList := {a, b, c, d, e}; (Defer[varList] /. OwnValues[varList])[[{1}, Ordering[varList]]] {e, d, c, b, a}

9

This is due to Sort on lists sorting by the size of the sub-list first, and only applying lexicographic sort for equal-size lists. This is in fact documented. Based on this observation, here is one possibility: ClearAll[lexicographicListSort] lexicographicListSort[lst_List] := Module[{lengths = Length /@ lst, ord}, ord = Ordering @ PadRight[lst, ...

8

If your operation can be converted to a canonical ranking rather than a pairwise comparison then you can use MaximalBy introduced in version 10. If not a good approach to a single pass through a list is Fold. Here is a function using that: foldMax[list_, p_] := Fold[If[p[##], ##] &, list] This proves to be faster in some cases than using Ordering ...

8

This is not a complete answer, but it's too long for a comment. It doesn't completely work, but perhaps it might inspire other answers. The idea is to use graph theory and flows. I shall just look at the 3x3 case. First we construct a graph of 9 source nodes and 9 sink nodes. The source nodes flow costlessly straight into the sink nodes, and the sink ...

7

Edit: 4x faster after refactoring and using {# - #2, +##} &[+##, Abs[# - #2]] & instead of Sort/@. Let we have the following 1D intervals $$[a_1,b_1], [a_2,b_2], [a_3, b_3].$$ Then we can take all these edges of intervals and sort them. For example, ...

7

If this is a bug it runs far deeper than SortBy. Since no one has yet been able to provide a reference for the intended ordering of Sort etc. it is hard to say with certainty. I can demonstrate that Sort, Ordering and Order all agree, even if I can't justify that result. x = {6/13 (4 - Sqrt[3]), 6/13 (4 + Sqrt[3])}; Outer[#@#2 &, {Order @@ # &, ...

7

I commented on this a bit here: What are the most common pitfalls awaiting new users? Since SortBy was introduced in Mathematica 6 it is preferred where applicable over Sort with a custom comparator. This is because SortBy uses vector application of its second argument over the sort expression then the fast internal sort/ordering function, whereas Sort ...

7

You basically want to permute the elements of the list among some specified set of permutations, and find the ordering of the list among these permutations that is canonically "first". The set of permutations you're interested in is a subgroup of the permutation group $S_n$, generated by two generators, one of which rotates all elements one position to the ...

6

I think this does what you want: Less @@ SortBy[Defer[Subscript[ω, #]] & /@ {1, 2, 11, 22}, N @@ # &]

6

There is also ... Ordering ClearAll[sortBy]; sortBy[list_, column_, ord_: Less] := list[[Ordering[list[[All, column]], All, ord]]] Examples: a = {{1, 2, 3}, {7, 1, 4}, {3, 5, 6}, {10, 7, 1}, {12, 4, 8}}; sortBy[a, 2] (* {{7,1,4},{1,2,3},{12,4,8},{3,5,6},{10,7,1}} *) sortBy[a, 2, Greater] (* {{10,7,1},{3,5,6},{12,4,8},{1,2,3},{7,1,4}} *) ...

6

I am not familiar with the specific output format you need but I think I can show you how to proceed. dat = Import["ExampleData/caffeine.xyz", {{"VertexTypes", "VertexCoordinates"}}]; dat2 = {#[[1, 1]], #[[All, 2]]} & /@ GatherBy[dat\[Transpose], First]; dat3 = {#, Length@#2, #2} & @@@ dat2; dat3 has this format: dat3 // TableForm \$\left( ...

6

As a followup to the answer by bill s, as of version 10, you should consider using Association instead of lists of rules. In this case, you could do the following: Sort[AssociationThread[{a, b, c, d, e}, {5, 4, 3, 2, 1.1}]] (* <|e -> 1.1, d -> 2, c -> 3, b -> 4, a -> 5|> *) and then Keys@% (* {e, d, c, b, a} *)

5

Ordering[Ordering[data]] (* {3,1,2} *)

5

In version 10, you can use MeshCoordinates[ConvexHullMesh[...]] as in RunnyKine's answer, but you need to re-order them using MeshCells: pentagon=N@Table[{Cos[2 Pi k /5], Sin[2 Pi k /5]}, {k, 5}] points = N@RandomSample[Join[pentagon, {{0, 0}}]] chm=ConvexHullMesh[points]; ordering=MeshCells[chm,2][[1,1]] out=MeshCoordinates[chm][[ordering]] ...

5

SortBy is usually a more concise form of Sort, yes, but at times, you may have data that cannot be expressed, or cannot be expressed elegantly, using SortBy. For example, let's suppose that we want to sort the following by age, ascending, then by name, descending: data = { <|"Name"->"Jill", "Age" -> 23|>, <|"Name"->"Jack", "Age" -> ...

4

Edit: This question closely related to one asked on Stack Overflow before the existence of Mathematica.SE. Please see this link for the history and examples: Unsort: remembering a permutation and undoing it See also: Ordering@Ordering and Ranking Permutations The first Q&A references a use of the Ordering method shown below from 2007 on ...

4

I propose using Order, assuming equal-length lists. Order[{1, 3, 5}, {1, 3, 4}] Order[{1, 3, 5}, {1, 5, 2}] Order[{1, 3, 5}, {1, 3, 5}] -1 1 0 You can assign an infix operator if you wish: CirclePlus = Order; {1, 3, 5} ⊕ {1, 3, 4} {1, 3, 5} ⊕ {1, 5, 2} {1, 3, 5} ⊕ {1, 3, 5} -1 1 0 You can convert the numeric output to Boolean as needed, ...

4

Horribly inefficient way to do such things. Use IntegerPartitions: set = Range@100; total = 400 s = Select[Tuples[set, 3], Total[#] == t &]; // Timing // First j = Sort[Join @@ Permutations /@ IntegerPartitions[total, {3}, set]]; // Timing // First s == j (* 12.948083 0. True *) The latter is below timing resolution... For your case, ...

4

Small example on 5x5 matrix: pp = Table[p[i, j], {i, 5}, {j, 5}] One way: pp[[#, #]] &@Insert[Rest@Range[5], 1, -2] Or another: pp[[;; 4, ;; 4]] = RotateLeft[pp[[;; 4, ;; 4]], {1, 1}];

4

No one has mentioned the difference in performance: SeedRandom[0]; data = RandomInteger[{-10000, 10000}, 10^5]; sdata = Sort[data, Abs[#1] < Abs[#2] &]; // AccurateTiming sbdata = SortBy[data, Abs]; // AccurateTiming sbstable = SortBy[data, {Abs}]; // AccurateTiming (* 1.86124 0.0222057 0.00999333 *) As mentioned by MarcoB, the results are ...

3

list1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; list2 = {"It", "is", "only", "the", "morning", "the", "man", "complained", "I", "shall", "consider", "nothing"}; GatherBy[Transpose[{list1, list2}], Mod[#[[1]], 3] &][[All, All, 2]] (* {{"It", "the", "man", "shall"}, {"is", "morning", "complained", "consider"}, {"only", "the", "I", ...

3

L1 = {{"Australia", a1}, {"USA", a2}, {"Norway", a3}}; L2 = {{"USA", b1}, {"Norway", b2}, {"Australia", b3}}; L2[[Flatten[Position[First /@ L2, #] & /@ First /@ L1]]] {{"Australia", b3}, {"USA", b1}, {"Norway", b2}} Or (revised as per Mr. Wizard's comments) Sort[L2][[Ordering @ Ordering @ L1]] {{"Australia", b3}, {"USA", b1}, {"Norway", ...

3

l1 = {{"a", a1}, {"b", a2}, {"c", a3}} l2 = {{"c", b3}, {"b", b2}, {"a", b1}} {#, # /. Rule @@@ l2} &[l1[[All, 1]]] // Transpose (* {{"a", b1}, {"b", b2}, {"c", b3}} *)

3

If you have Version 10, you could use ConvexHullMesh. pts = RandomReal[{-10, 10}, {6, 2}]; You can then order them by doing: chull = ConvexHullMesh[pts]; And here are the points: MeshCoordinates[chull] Note: This does not always order the points but one can use MeshCells which will give the ordering correctly. See @kguler's answer.

Only top voted, non community-wiki answers of a minimum length are eligible