Sorting Arrays

Element6

Well-known member
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Jun 30, 2008
Messages
611
Location
Denver Co, USA
Programming Experience
1-3
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Feb 25, 2009
Messages
158
Programming Experience
5-10
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
Joined
Dec 17, 2005
Messages
15,431
Location
Norway
Programming Experience
10+
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
Joined
Jun 30, 2008
Messages
611
Location
Denver Co, USA
Programming Experience
1-3
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Jun 28, 2004
Messages
465
Location
New York
Programming Experience
10+
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
Joined
Dec 17, 2005
Messages
15,431
Location
Norway
Programming Experience
10+
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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

Array.Sort(num, AddressOf AbsSort)
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

Array.Sort(num, AddressOf AbsSort)
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

Array.Sort(num, AddressOf AbsSort)
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
Joined
Aug 17, 2004
Messages
14,322
Location
Sydney, Australia
Programming Experience
10+
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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

        Array.Sort(AnArrayOfNumbers, AddressOf AbsSort)

        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
Joined
Dec 17, 2005
Messages
15,431
Location
Norway
Programming Experience
10+
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
Joined
Dec 17, 2005
Messages
15,431
Location
Norway
Programming Experience
10+
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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
        Array.Sort(AnArrayOfNumbers, AddressOf AbsSortOfN)

        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
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
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
        Array.Sort(AnArrayOfNumbers, AddressOf AbsSortOfN)
        Return AnArrayOfNumbers
    End Function
Yikes!
 
Top Bottom