Jump to content

Reference sorting?


Champak
 Share

Go to solution Solved by Melba23,

Recommended Posts

I need a multiD array sorted a very specific way that...I don't think....can be achieved a "normal" way and instead would need a reference to sort it. What I'm imagining is set up a reference array with things sorted in the way that I want, and then the array that needs to be sorted looks at that and sorts it's contents in the same manner, skipping anything that it doesn't contain. Is this type of sorting possible? I tried searching custom sort and reference sort.

Ex I'm sorting sizes so I'll have,

3-6M, 3-9M, 2T, 2, 3, 3T, 12M, 12, 12-18M, 3 US, 4 US, 12 US

and I would need it sorted as

3-6M, 3-9M, 12M, 12-18M, 2, 2T, 3, 3T, 12, 3 US, 4 US, 12 US

If a "reference sort" is not possible, how can I go about getting this done? Off the top of my head the only way I can imagine is looping through the reference with a search and copying that row to a new array until I rebuild it in the order that I want.

Thanks

Edited by Champak
Link to comment
Share on other sites

Link to comment
Share on other sites

You may want to check out @Melba23's ArrayMultiColSort UDF, it gives a bit more control over sorting, and you can sort by different columns, so you could separate the suffixes (M, T, US) and sort by that column, then the numbers. There's also the ability to set the sort order with strings, though I haven't used this functionality so I can't really guide on it. From the documentation: "Sort order can be either numeric (0/1 = ascending/descending) or a ordered string of items"

 

Besides that, I think maybe an example script/data that we could see would be helpful.

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

I'm just shamelessly advertising:
With >>this UDF<< you can use a completely arbitrary comparison function for sorting (and other tasks).
In this way you are completely free how data should be sorted.
You can write your own algorithm, just as you can use a fixed comparison array.
So the whole magic is not in the sorting, but in the greater than/smaller than/equal to comparison of values.

Your example from above, for example, is how I would have implemented it:

#include "ArrayPlus.au3"

; the array to be sorted
Global $aArray[] = ["3-6M", "3-9M", "2T", "2", "3", "3T", "12M", "12", "12-18M", "3 US", "4 US", "12 US" ]

; sort with own comparison function
_ArraySortFlexible($aArray, _myRefCompare)

; print the result
_ArrayDisplay($aArray, "the sorted array")


; user defined function to compare 2 values for smaller, equal, less
Func _myRefCompare($A, $B)
    ; the reference
    Local Static $aRefSort[] = ["3-6M", "3-9M", "12M", "12-18M", "2", "2T", "3", "3T", "12", "3 US", "4 US", "12 US"]

    ; check if the current elements occur in the reference array.
    For $i = 0 To UBound($aRefSort) - 1
        If $A = $aRefSort[$i] Then Return -1
        If $B = $aRefSort[$i] Then Return 1
    Next

    ; if both values do not appear in the reference array, use natural sorting.
    Return __ap_cb_comp_Natural($A, $B)
EndFunc

 

But of course 2D arrays work too (more dimensions don't work):

Spoiler
#include "ArrayPlus.au3"

; the array to be sorted
Global $aArray[][] = [["3-6M", 1, 2, 3], ["3-9M", 1, 2, 3], ["2T", 1, 2, 3], ["2", 1, 2, 3], ["3", 1, 2, 3], ["3T", 1, 2, 3], ["12M", 1, 2, 3], ["12", 1, 2, 3], ["12-18M", 1, 2, 3], ["3 US", 1, 2, 3], ["4 US", 1, 2, 3], ["12 US", 1,2,3]]

; sort with user-defined comparison function
_ArraySortFlexible($aArray, _myRefCompare)

; print the result
_ArrayDisplay($aArray, "the sorted array")


; user defined function to compare 2 values for smaller, equal, less
Func _myRefCompare($A, $B)
    ; the reference
    Local Static $aRefSort[] = ["3-6M", "3-9M", "12M", "12-18M", "2", "2T", "3", "3T", "12", "3 US", "4 US", "12 US"]

    ; check if the current elements occur in the reference array.
    For $i = 0 To UBound($aRefSort) - 1
        If $A[0] = $aRefSort[$i] Then Return -1
        If $B[0] = $aRefSort[$i] Then Return 1
    Next

    ; if both values do not appear in the reference array, use natural sorting.
    Return __ap_cb_comp_Natural($A[0], $B[0])
EndFunc

 

 

Link to comment
Share on other sites

Here is a SQLite approach but @Nine's question is still valid.

#include <Array.au3>
#include <SQLite.au3>

Local $aSizes = ['3-6M', '3-9M', '2T', '2', '3', '3T', '12M', '12', '12-18M', '3 US', '4 US', '12 US']

$aSorted = SortSizes($aSizes)
_ArrayDisplay($aSorted)

Func SortSizes(ByRef $aSizes)
    Local $hDB, $N1, $N2, $Alpha
    _SQLite_Startup()
    $hDB = _SQLite_Open()
    _SQLite_Exec($hDB, 'CREATE TABLE Sizes(N1 INT, N2 INT, ALPHA VARCHAR(4));')
    For $Index = 0 To UBound($aSizes) - 1
        $N1 = StringRegExp($aSizes[$Index], '\G\d+', 3)
        $N1 = IsArray($N1) ? Number($N1[0]) : 0
        $N2 = StringRegExp($aSizes[$Index], '\d+\-\K\d+', 3)
        $N2 = IsArray($N2) ? Number($N2[0]) : 0
        $Alpha = StringRegExp($aSizes[$Index], '[a-zA-Z]+', 3)
        $Alpha = IsArray($Alpha) ? $Alpha[0] : ''
        _SQLite_Exec($hDB, 'INSERT INTO Sizes(N1, N2, ALPHA)' & _
        'VALUES(NULLIF(' & $N1 & ', 0), NULLIF(' & $N2 & ', 0),' & _SQLite_FastEscape($Alpha) & ');')
    Next
    Local $aResult, $iRows, $iCols
    _SQLite_GetTable2D($hDB, _
        'SELECT N1 || (CASE WHEN N2 IS NULL THEN "" ELSE "-" END) || COALESCE(N2, "") || " " || ALPHA AS Result ' & _
        'FROM Sizes ORDER BY ALPHA, N1, N2;', $aResult, $iRows, $iCols)
    _SQLite_Close($hDB)
    _SQLite_Shutdown()
    _ArrayDelete($aResult, 0)
    Return $aResult
EndFunc

 

When the words fail... music speaks.

Link to comment
Share on other sites

  • Moderators
  • Solution

Champak,

mistersquirrle kindly pointed at my UDF - here it is in action:

#include <Array.au3>

#include "ArrayMultiColSort.au3"

; Set required sort list
$sList = "3-6M,3-9M,12M,12-18M,2,2T,3,3T,12,3 US,4 US,12 US"
; Get an array
$aList = StringSplit($sList, ",", 2)
; Shuffle it
_ArrayShuffle($aList)
; Make 2D (min required)
_ArrayColInsert ($aList, 1)
; And here is the result
_ArrayDisplay($aList, "Shuffled", Default, 8)

; Set list in correct format for the UDF
Global $aSortData[][] = [[0, $sList]]

; Sort the array using the required sort date
_ArrayMultiColSort($aList, $aSortData)
; And here it is
_ArrayDisplay($aList, "Sorted", Default, 8)

Good enough?

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

My 2 cents, using regex to make a template (could be easily adapted)

Edit
Nine is right. This one is based on the rule : "M" types first, then "digit" or "digit-T" types, then " US" types

#Include <Array.au3>

Local $arr[12] = ["3-6M", "3-9M", "2T", "2", "3", "3T", "12M", "12", "12-18M", "3 US", "4 US", "12 US"] 
; to get : 3-6M, 3-9M, 12M, 12-18M, 2, 2T, 3, 3T, 12, 3 US, 4 US, 12 US

_ArrayColInsert ($arr, 1)
For $i = 0 to UBound($arr)-1
    If StringRegExp($arr[$i][0], '^[\d-]+M$') Then _ 
        $arr[$i][1] = StringFormat("%06i", Number(StringReplace($arr[$i][0], "-", "."))*100)
    If StringRegExp($arr[$i][0], '^\d+$') Then _ 
        $arr[$i][1] = StringFormat("%06i", Number($arr[$i][0] & "0")*100)
    If StringRegExp($arr[$i][0], '^\d+T$') Then _ 
        $arr[$i][1] = StringFormat("%06i", Number(StringReplace($arr[$i][0], 'T', "1"))*100)
    If StringRegExp($arr[$i][0], '^\d+ US$') Then _ 
        $arr[$i][1] = StringFormat("%06i", Number(StringReplace($arr[$i][0], ' US', "00"))*100)
Next
;_ArrayDisplay($arr)
_ArraySort($arr, 0, 0, 0, 1)
_ArrayColDelete($arr, 1, True)
_ArrayDisplay($arr)

 

Edited by mikell
Link to comment
Share on other sites

Thanks all of you. I'm going to try all of them out.

These are children's clothing. Things with "M" are months (infants, babies), sizes without a letter or "T" are toddlers and young children, sizes with US are shoes. So let's say I were to just order all the 3s, it would go "NB, 0-3M, 3M, 3-6M, 3-9M, 3, 3T, 3 US". The specific order makes it easy to find what is needed.

Edited by Champak
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...