Impossible to sort Sym elements

I’m trying to order elements (Sym) from a Tuple. I’ve tried several codes but nothing works.

I will be grateful if anyone can help.

using SymPy
using LinearAlgebra

a1 = [Sym("a_$i^$j") for i=1 for j=1:2]
a2 = [Sym("a_$i^$j") for i=2 for j=1:2] 
A = [a1,a2] # conjunto de todas as ações
S = vec(collect(Base.product(A...))) #Cartesian product

SymPy.sort!(S, by = x -> S[1])

Is that just a typo? S[1] should be x[1]:

SymPy.sort!(S, by = x -> x[1])
1 Like

You are right, this is the most correct way.
i tried that too.
But the result is still not the desired one:

8-element Array{Tuple{Sym,Sym,Sym},1}:
(a_1^1, a_2^1, a_3^1)
(a_1^2, a_2^1, a_3^1)
(a_1^1, a_2^2, a_3^1)
(a_1^2, a_2^2, a_3^1)
(a_1^1, a_2^1, a_3^2)
(a_1^2, a_2^1, a_3^2)
(a_1^1, a_2^2, a_3^2)
(a_1^2, a_2^2, a_3^2)

The result I want is:

(a_1^1, a_2^1, a_3^1)
(a_1^1, a_2^1, a_3^2)
(a_1^1, a_2^2, a_3^1)
(a_1^1, a_2^2, a_3^2)
(a_1^2, a_2^1, a_3^1)
(a_1^2, a_2^1, a_3^2)
(a_1^2, a_2^2, a_3^1)
(a_1^2, a_2^2, a_3^2)

There is no order defined on the Julia representation of a Sym object, but you can workaround with e.g.

sort(S, by = x -> String(Symbol(x[1])) )
5 Likes

perfect
thank you

sort also accepts a keyword argument lt (standing for less-than) which defaults to isless. Since isless doesn’t seem to be useful for Syms, you can set a comparison manually. If you want it to follow the string order, you can do:

sort(S, by = first, lt = (x, y) -> string(x) < string(y))

You can also adjust the by argument accordingly, as suggested above:

sort(S, by = string ∘ first)
2 Likes

thanks @tomerarnon ,

The code, written in this way, is more understandable. But it does not allow to order columns 2 and 3.

I managed to sort all the columns using the following code:

S1 = sort(S, by = a -> String(Symbol(a[3])))
S2 = sort(S1, by = a -> String(Symbol(a[2])))
S3 = sort(S2, by = a -> String(Symbol(a[1])))

8-element Array{Tuple{Sym,Sym,Sym},1}:
(a_1^1, a_2^1, a_3^1)
(a_1^1, a_2^1, a_3^2)
(a_1^1, a_2^2, a_3^1)
(a_1^1, a_2^2, a_3^2)
(a_1^2, a_2^1, a_3^1)
(a_1^2, a_2^1, a_3^2)
(a_1^2, a_2^2, a_3^1)
(a_1^2, a_2^2, a_3^2)

It does like this

sort(S, lt = (x, y) -> string(x[1]) < string(y[1]) || string(x[1])==string(y[1]) && string(x[2]) < string(y[2]) || string(x[2])==string(y[2]) && string(x[3]) < string(y[3]))

and it also doesn’t require a stable sort algorithm that applying sort multiple times does.

You could simplify and generalize with reduce or a comprehension.

2 Likes

The way you used is fine, but note that you can just use string(...), rather than String(Symbol(...)) as I did in my second example.

However, just to demonstrate that you can in fact sort by any column:

# with `lt`
sort(S, by = x->x[2], lt = (x, y) -> string(x) < string(y))

# or using composition in `by`
sort(S, by = string ∘ (x -> x[2]))

So anything is possible :wink:

Also, it is now apparent that what you want is simply:

sort(S, by = string)

which will sort the entries in lexicographic order of their strings, which in this case will sort by first character, then second character, then third, and so on. So if your variables are named as you’ve shown, this will work.

2 Likes

thanks @tomerarnon

This greatly improved my code.