# Sorting Arrays

#### Element6

##### Well-known member
Ok well .NET definately makes sorting Arrays easy. I have a quick question though if anyone knows.

I am using the Array type .Sort function to sort my array.

By default it places the result Array into Ascending order Least to Greatest

How do I change that to Descending order Greatest to Least?
and
How do I change it to Closest to logic? or does that not exist?

Assume there is an Array of Numbers 0,13,21,-2,4,5,1.34 and I want them to sort closest to 0 or some other arbitray value; the Output should look similar to:

0,1.34,-2,4,5,13,21

Is there anyway of doing this? or do I have to write the routine?

#### newguy

##### Well-known member
Unfortunately the sort method is terrible with numbers. It will list them like 1,11,2,21,3 which makes no sense to me. I just think it was just laziness.

#### Element6

##### Well-known member
Well there is a trick with numbers and sorting them; an old lazy developers trick us out-of-date developers do.

Convert your numbers in segments of 2 digits at a time to a character and store them as characters, with an indicator to reconvert to numbers. So when you pass them through sort algorithms you get the same result as if they were literal.

Be sure to start your map at 33-132 so that you map 0-99 to 33-132 using a 33 offset. That way you get usable characters.

Then just concat the characters and you get a nice string expression that is encoded numerical data. Do a quick sort. La Poof! Wala, sorted numbers.

I'm lazy, I hate programming too much if I can help it so I do stupid stuff like that so I don't have to.

Ok, well I had to write a Closest to Zero Sort alogrithm, *sigh* I always do stuff noone else develops; *starting to wonder if I my logic is skewed or everyone elses is.*

#### picoflop

##### Well-known member
Numbers are sorted perfectly!

VB.NET:
``````Dim a() As Integer = {1, 11, 2, 22, 5}
Array.Sort(a)
For Each i As Integer In a
Debug.Print(i)
Next``````
Unfortunately ... many people think that "11" is number. It's not. It's a ... string! Also some ppl think that "dim a as string = 5" makes "a" a "number". No. "a" is still a string.

Do yourself a favor and use "Option Strict ON" ...

#### JohnH

##### VB.NET Forum Moderator
Staff member
VB.NET:
``````Dim num() As Single = {0, 13, 21, -2, 4, 5, 1.34}
Array.Sort(num, Function(x As Single, y As Single) Math.Abs(x).CompareTo(Math.Abs(y)))``````
If you don't support Lambda expressions you have to make that a real Function and use AddressOf operator in Sort call.

#### newguy

##### Well-known member
Your right, it has been a while since I played with that. It is a listbox that does not sort numbers correctly.

#### Element6

##### Well-known member
Thanks for the listbox hint; but I'm trying to keep my code small not trying to include things I don't need and grow a normally 1mb .exe into 200mb file which WILL occur if I had all those gadgets.

The sort function needs to be written I think end of story. This is a console application and is intended to migrate to a service not an application front-end.

Microsoft does a great job on useful other stuff like the listbox, but... They forget people do have other constraints. Such as "Security", and Memory and disk management.

Sometimes the best solution; is just write the code.

And for those that are getting to know me, I AM very nit picky about security and code optimization. Things that are one time fly-bys; dont get controls they get written; others that are intensive I inculde.

#### Solitaire

##### Well-known member
In order to reverse the sort from ascending to descending, first do a regular sort, and then do

Array.Reverse(arrayname)

Make sure you sort it first. The Array.Reverse() method will simply rearrange the values from top to bottom without sorting them.

#### JohnH

##### VB.NET Forum Moderator
Staff member
Element6 said:
The sort function needs to be written I think end of story.
Since you didn't understand I will post the non-lambda function spelled out for you also:
VB.NET:
``````Function AbsSort(x As Single, y As Single) As Integer
Return Math.Abs(x).CompareTo(Math.Abs(y))
End Function``````
VB.NET:
``Array.Sort(num, AddressOf AbsSort)``
Application type is not relevant here. I do recommend you start out with VB 2008 though, even VB 2010 is right around the corner now (RC). VB 2005 you say you are using is out-dated now.
Solitaire said:
In order to reverse the sort from ascending to descending, first do a regular sort, and then do
It would be better to just swap the operands in the CompareTo expression, that is, if a "reverse" sort was needed, which it is not here.

#### Element6

##### Well-known member
Ok. I understand the code.

Except I need to expand on the code you provided.

My origional problem was Closest to 0; I later clarified Closest to N. Ideally, I want to send the offset as N how would I pass the parameter of N in this case?

VB.NET:
``````num() = {3, 12, -.123, 5.1, 1002, 23}

Function AbsSort(x As Single, y As Single) As Integer
Return Math.Abs(x).CompareTo(Math.Abs(y))
End Function

Pseduo Code of :
VB.NET:
``````num() = {3, 12, -.123, 5.1, 1002, 23}

Function AbsSort([B][I]n as decimal[/I][/B], x As Single, y As Single) As Integer
Return Math.Abs(x[B][I]-n[/I][/B]).CompareTo(Math.Abs(y)[B][I]+n[/I][/B])
End Function

How do I determine my signs?

The only solution I know works (doesn't mean it's the only one available), I much rather do it the way you have expressed it can be done, is...

Take the array (num)
Create 2 temporary Arrays (NumLower, NumUpper)
Move everything that is lower then N into NumLower
Move everything that is Higher or equal to N into NumUpper
Sort NumLower and NumUpper

Recombine according to Values differences.

Are you suggesting something like
VB.NET:
``````num() = {3, 12, -.123, 5.1, 1002, 23}

Function AbsSort([B][I]n as decimal[/I][/B], x As Single, y As Single) As Integer
Dim x1 as single = x
Dim y1 as single = y
If (x>n) then
x1 = x-n
y1 = y+n
Else
x1 = x+n
y1 = y-n
End If
Return Math.Abs([B][I]x1[/I][/B]).CompareTo(Math.Abs([B][I]y1[/I][/B]))
End Function

I would rather sort using the above method; if you can suggest away of passing N that I am totally overlooking.

Last edited:

#### jmcilhinney

##### VB.NET Forum Moderator
Staff member
JohnH is quite correct of course, but for more information on sorting arrays and collections, you might like to follow the Blog link in my signature and check out my three part post on the subject.

#### Element6

##### Well-known member
I am sure he is. The approach seems valid enough. I just don't know how to pass the N offset.

#### Element6

##### Well-known member
Error; I'm sorry sometimes I can ask stupid questions without looking at the problem.

Wil this work? Haven't tried it yet.
VB.NET:
``````    Public Function AbsSort(ByVal x As Decimal, ByVal y As Decimal) As Integer
Return Math.Abs(x).CompareTo(Math.Abs(y))
End Function

Public Function SortClosestToN(ByVal AnArrayOfNumbers As Decimal(), ByVal ValueOfN As Decimal) As Decimal()
Dim x As Long

For x = 0 To AnArrayOfNumbers.Length - 1
AnArrayOfNumbers(x) = AnArrayOfNumbers(x) - ValueOfN
Next

For x = 0 To AnArrayOfNumbers.Length - 1
AnArrayOfNumbers(x) = AnArrayOfNumbers(x) + ValueOfN
Next

Return AnArrayOfNumbers
End Function

Sub Main()
Dim num() As Decimal = {3, 12, -0.123, 5.1, 1002, 23}

num = SortClosestToN(num, 33)
End Sub``````
My logic was way out wack and I was looking at the problem from a process level not a mathematics one.

Last edited:

#### JohnH

##### VB.NET Forum Moderator
Staff member
VB.NET:
``Math.Abs(x - n).CompareTo(Math.Abs(y - n)``
With same data array the result where n=4 is:
4, 5, 1.34, 0, -2, 13, 21
If you have to use the explicit function you have to declare 'n' as a private field so that the function can access it (inline any local variable will do). The Comparison(Of T) delegate signature can't be changed.

#### Element6

##### Well-known member
How am I passing N into the AbsSort?

That was my first impression mathematically.

But, I don't know if AbsSort will be handled correctly.

Is the order of operation value1 (Required) value2 (Required) n (optional = 0) or
reversed?

#### Element6

##### Well-known member
Just checked; if I pass N as optional

Error 2 Overload resolution failed because no accessible 'Sort' can be called with these arguments:

'Public Shared Sub Sort(Of T)(array() As T, comparison As System.Comparison(Of T))': Method 'Public Shared Function AbsSort(x As Decimal, y As Decimal, n As Decimal) As Integer' does not have a signature compatible with delegate 'Delegate Function Comparison(Of T)(x As T, y As T) As Integer'.
'Public Shared Sub Sort(Of T)(array() As T, comparison As System.Comparison(Of T))': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
'Public Shared Sub Sort(Of Decimal)(array() As Decimal, comparer As System.Collections.Generic.IComparer(Of Decimal))': 'AddressOf' expression cannot be converted to 'System.Collections.Generic.IComparer(Of Decimal)' because 'System.Collections.Generic.IComparer(Of Decimal)' is not a delegate type.
'Public Shared Sub Sort(Of TKey, TValue)(keys() As TKey, items() As TValue)': Type parameter 'TValue' cannot be inferred.
'Public Shared Sub Sort(array As System.Array, comparer As System.Collections.IComparer)': 'AddressOf' expression cannot be converted to 'System.Collections.IComparer' because 'System.Collections.IComparer' is not a delegate type.
'Public Shared Sub Sort(keys As System.Array, items As System.Array)': 'AddressOf' expression cannot be converted to 'System.Array' because 'System.Array' is not a delegate type. ..\GlobalFunctions.vb 605 9 AISystem

#### JohnH

##### VB.NET Forum Moderator
Staff member
Element6 said:
How am I passing N into the AbsSort?
JohnH said:
If you have to use the explicit function you have to declare 'n' as a private field so that the function can access it (inline any local variable will do). The Comparison(Of T) delegate signature can't be changed.
You don't know how to declare a private field? This is also sometimes referred to as "module level scope", see Scope in Visual Basic
VB.NET:
``Private n As Single``

#### Element6

##### Well-known member
Thats a hack and you know it.

Of course I know how to, but the implementation I am using is being called as a form of a delegate and the function cannot use global passes in this case.

This works, but not for my implementation
VB.NET:
`````` Public SortN As Decimal = 0.0

Public Function AbsSortOfN(ByVal x As Decimal, ByVal y As Decimal) As Decimal
Return Math.Abs(x - SortN).CompareTo(Math.Abs(y - SortN))
End Function

Public Function SortClosestToN(ByVal AnArrayOfNumbers As Decimal(), ByVal n As Decimal) As Decimal()
SortN = n

Return AnArrayOfNumbers
End Function``````
Let me give you some background on what I am doing; it should make it easier to understand why this won't work.

I am calling code from outside the application and multi-threaded. So private declares wouldn't work because I might end up with instances overlapped; I need to pass it as a function parameter per instance per compare.

So the logical step is passing the value as N; not referring it, to guarentee that each invoke contains the correct data. Otherwise I can end up with multiple calls changing the private global value and messing up the threading returns. If that makes sense.

The only other solution is keep the value of N in a per thread global param; and that becomes memory intensive after a while as a matter of principal. It's just simpler to pass N.

Do I have to create state data to represent a value of N per thread or is there a way of blending the data so the value of N can be extrapulated?

#### Element6

##### Well-known member
This is the other solution and it is very ugly in my opinion

VB.NET:
``````    Public SortN As Decimal = 0.0

Public Function AbsSortOfN(ByVal x As Decimal, ByVal y As Decimal) As Decimal
Dim localN As Decimal = SortN
Dim Value As Decimal

Value = Math.Abs(x - localN).CompareTo(Math.Abs(y - localN))
SortN = localN

Return Value
End Function

Public Function SortClosestToN(ByVal AnArrayOfNumbers As Decimal(), ByVal n As Decimal) As Decimal()
SortN = n