Sort by last column / item in list?

Technical support and scripting issues

Moderators: Dorian (MJT support), JRL

Post Reply
User avatar
Phil Pendlebury
Automation Wizard
Posts: 543
Joined: Tue Jan 16, 2007 9:00 am
Contact:

Sort by last column / item in list?

Post by Phil Pendlebury » Wed Jul 31, 2013 2:44 pm

Hi all,

Maybe I am just having a bad day today but I'm stuck on a simple way to do this within MSched. ie. Without exporting to CSV or Excel etc.

I have a list of many items like this:

Code: Select all

file;563547215;0;Z:\Z - Manuals\PR\B.txt
file;5645215;0;Z:\Z - Manuals\PR\C.txt
file;3457215;0;Z:\Z - Manuals\PR\A.txt
file;55415;0;Z:\Z - Manuals\PR\D.txt
And so on (maybe a thousand items).

I want to sort the list by the last value - ie: "Z:\Z - Manuals\PR\B.txt"

The areas are delimited by ";" so sort by the 4th "column" BUT maintain the data as it is. So it would become:

Code: Select all

file;3457215;0;Z:\Z - Manuals\PR\A.txt
file;563547215;0;Z:\Z - Manuals\PR\B.txt
file;5645215;0;Z:\Z - Manuals\PR\C.txt
file;55415;0;Z:\Z - Manuals\PR\D.txt
Can anyone suggest the simple route? Obviously I can separate the lines using ";" but how do I sort by the last element and keep the rest of each "row" intact.

Just incase it is not clear - Imagine 4 columns in Excel. I want to sort the rows by the 4th column.

Any guidance appreciated. Thanks. P :)
Phil Pendlebury - Linktree

User avatar
Phil Pendlebury
Automation Wizard
Posts: 543
Joined: Tue Jan 16, 2007 9:00 am
Contact:

Post by Phil Pendlebury » Thu Aug 01, 2013 1:11 pm

OK well I have done this in about 60 lines using multiple loops and arrays and then writing back after comparing a sorted version.

It was a surprisingly awkward task but I may well have done it rather inefficiently...

If anyone wants more info let me know.
Phil Pendlebury - Linktree

djs
Junior Coder
Posts: 47
Joined: Sun Apr 29, 2012 4:21 pm

Post by djs » Thu Aug 01, 2013 6:57 pm

Use the bubble sort routine that Marcus posted a while back.

http://www.mjtnet.com/forum/viewtopic.php?p=14303

This is exactly the type of thing that bubble sorts do.

In fact, I would recommend having the bubble sort as part of your code library. Its a very useful tool.

Dan

User avatar
Phil Pendlebury
Automation Wizard
Posts: 543
Joined: Tue Jan 16, 2007 9:00 am
Contact:

Post by Phil Pendlebury » Thu Aug 01, 2013 7:31 pm

Hi Don,

Sorry but I think you didn't understand my post. I am aware of bubble sort. In fact I have written my own sort routines many times of varying kinds (since back in the Spectrum days. Hehe).

Also as mentioned above, bubble sort is kind of obsolete in MSched (I do say "kind of", not completely), now that we have array sort (one command). Or indeed even using cmd sort (one command).

The challenge of the above question was the fact that the sorting must be done on only the last part (column) of a string, where the first part is always different, maintaining the string in tact once sorted.

As I said, I have accomplished it now anyway, including reading and writing to registry once sorted, but I was hoping someone may have an alternative insight on how it could be done.

Thanks again anyway.
Phil Pendlebury - Linktree

User avatar
JRL
Automation Wizard
Posts: 3526
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Fri Aug 02, 2013 10:02 pm

Phil,

I know you've solved your problem already but I thought this was a fairly straight forward solution and you said, "It was a surprisingly awkward task but I may well have done it rather inefficiently... ". So this might be less awkward.

Information sources for this script sample are:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
For Schema.ini information.

http://www.mjtnet.com/forum/dbquery-dir ... t=sqltocsv
For Marcus' SQLToCSV VBScript

And:
http://www.mjtnet.com/blog/2013/03/27/g ... installed/
I could be wrong, but I believe that if you don't have office installed, this solution will not work for you without the Microsoft Office Data Connectivity Components mentioned on this blog page. I'm not really sure because I don't have any computers to test on that don't already have ODBC drivers installed. Perhaps someone else can clarify this issue.

Phil, you stated you didn't want to resort to using excel and I don't know if this script violates your rule or not.

This script uses SQL's "order by" function to sort by the text file's fourth column. We use the schema.ini file to tell the Microsoft driver that the delimiter is a semicolon ";". Then process the SQL line through VBScript.

More explanation in the comments.

Hope someone finds this useful,
Dick

Code: Select all

//Load the VBScript
GoSub>VBScript

/*
Create and/or cleanup the folder
I like to keep schema using script created files in a unique
folder so that schema.ini files don't interfere with each other.
"Schema.ini" must have that exact name and reside in with the
files its formatting
*/
CreateDir>%temp_dir%__SchemaSample
DeleteFile>%temp_dir%__SchemaSample\Schema.ini
DeleteFile>%temp_dir%__SchemaSample\PhilText.txt
DeleteFile>%temp_dir%__SchemaSample\SortedPhilText.txt

//Write Schema.ini to the folder
LabelToVar>Schema,vSchemaData
WriteLn>%temp_dir%__SchemaSample\Schema.ini,wres,vSchemaData

//Write Phil's sample data to the folder
LabelToVar>Sampletext,vSampleData
Let>WLN_NOCRLF=1
WriteLn>%temp_dir%__SchemaSample\PhilText.txt,wres,vSampleData
Let>WLN_NOCRLF=0

//Set up the parameters and run modified SQLToCSV
Let>con=Driver={Microsoft Text Driver (*.txt; *.csv)}; Dbq=%temp_dir%__SchemaSample\;
Let>sql=select * from PhilText.txt order by F4
Let>oFile=%temp_dir%__SchemaSample\SortedPhilText.txt

VBRun>SQLToCSV,con,sql,oFile

//ReadFile and remove Header added by schema.ini and SQL
ReadFile>%temp_dir%__SchemaSample\SortedPhilText.txt,vData
StringReplace>vData,F1;F2;F3;F4%crlf%,,vData
MDL>vData


/*
Sampletext:
file;563547215;0;Z:\Z - Manuals\PR\B.txt
file;5645215;0;Z:\Z - Manuals\PR\C.txt
file;3457215;0;Z:\Z - Manuals\PR\A.txt
file;55415;0;Z:\Z - Manuals\PR\D.txt
*/


/*
Schema:
[PhilText.txt]
Format=Delimited(;)
ColNameHeader=False
*/


//Modified SQLToCSV the write in phil's format
SRT>VBScript
VBSTART
  Sub SQLToCSV(connection_string,sql_string,output_file)
    Dim outFile, objConnection, objRecordSet, strSQL, intCount
    set outFile = CreateObject("Scripting.FileSystemObject").CreateTextFile(output_file)
    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.open connection_string
    Set objRecordSet = objConnection.Execute(sql_string)
    for intcount = 0 to objRecordSet.fields.count -1
        if intcount <> objRecordSet.fields.count-1 then
            outFile.write objRecordSet.fields(intcount).name & ";"
        else
            outFile.write objRecordSet.fields(intcount).name
        end if
    next
    outFile.writeline ""
    do while not objRecordSet.eof
        for intcount = 0 to objRecordSet.fields.count - 1
        if intcount <> objRecordSet.fields.count-1 then
            outFile.write objRecordSet.fields(intcount).value & ";"
        else
            outFile.write objRecordSet.fields(intcount).value
        end if
        next
        outFile.writeline ""
        objRecordSet.movenext
    loop
    objRecordSet.Close
    set objRecordSet = Nothing
    objConnection.Close
    set objConnection = Nothing
    outFile.Close
    set outFile = Nothing
  End Sub
VBEND
END>VBScript

User avatar
Phil Pendlebury
Automation Wizard
Posts: 543
Joined: Tue Jan 16, 2007 9:00 am
Contact:

Post by Phil Pendlebury » Sat Aug 03, 2013 10:09 am

Hi JRL,

Thanks ever so much for looking that over. Your solution is very elegant.

I do have office installed and I did toy with using that but (as mentioned) I wanted to do this without exporting any files to CSV or txt or anything else.

Also I wanted it to be usable by anyone.

And finally I wanted to understand what I was doing - I don't know VBS at all and always avoid if I can.

Anyway here is my solution which will look messy until I get chance to clean up but actually it is not that bad really.
  • It just reads each key to an array and then separates the last part to another array.
    Sorts the last part using array sort. (One command).
    Then find the sorted part in the original array and when found copy the whole key to a new array.
    Then of course writeback to registry.
So there is some code here that is specific to the nature of the keys (ie reading and writing reg):

Code: Select all

Let>APP_TITLE=Phil P - MPC Faves Sorter
Let>MSG_HEIGHT=200
Let>MSG_WIDTH=800
// For 64 Bit Registry
Let>REG_64=1
// Read number of entries
RegistryEnumVals>HKEY_CURRENT_USER,Software\Gabest\Media Player Classic\Favorites\Files,strVals
Separate>strVals,CRLF,NamesArr
Let>Amount=NamesArr_Count-1
// Make arrays for future use
ArrayDim>FullList,Amount
ArrayDim>PathOnly,Amount
ArrayDim>Final,Amount
//
Let>Loop=0
//
Label>Start
Let>Entry=Name%Loop%
Let>PlusOne=Loop+1
// Read an item
RegistryReadKey>HKEY_CURRENT_USER,Software\Gabest\Media Player Classic\Favorites\Files,%Entry%,MPCFAVS64
If>%MPCFAVS64%=
  GOTO>ENDREAD
ENDIF
// Get and path only and add to array "PathOnly" 
Separate>%MPCFAVS64%,;,FavBits
//
Let>FullList_%PlusOne%=%MPCFAVS64%
Let>PathOnly_%PlusOne%=FavBits_4
//
Let>Loop=Loop+1
GOTO>Start
//
Label>ENDREAD
////////////////////////////////////
// END OF PART 1
////////////////////////////////////
// Delete the old key
RegistryDelKey>HKEY_CURRENT_USER,Software\Gabest\Media Player Classic\Favorites\Files
// Sort the array that contains the path only
ArraySort>PathOnly
//
Let>NewLoop=1
Label>Start2
Let>Sorted=PathOnly_%NewLoop%
//
// Compare sorted array to unsorted and copy to new array when found 
//
Let>InnerLoop=1
Label>INNERSTART
Let>Compare=FullList_%InnerLoop%
Separate>%Compare%,;,ComparePath
Let>Test=ComparePath_4
//
IF>%Test%=%Sorted%
 Let>Final_%NewLoop%=%Compare%
 Let>KeyNum=%NewLoop%-1
 Let>Key=Name%KeyNum%
 //
 //Write new item to registry
 RegistryWriteKey>HKEY_CURRENT_USER,Software\Gabest\Media Player Classic\Favorites\Files,%Key%,%Compare%
 //
 GOTO>NextMove
ENDIF
//
Let>InnerLoop=InnerLoop+1
GOTO>INNERSTART
Label>NextMove
//
Msg>Sorted: %NewLoop% of %Amount%%CRLF%%CRLF%Found at %InnerLoop%:%CRLF%%Sorted%
//
If>%NewLoop%=%Amount%
  GOTO>END2
ENDIF
Let>NewLoop=NewLoop+1
//
GOTO>Start2
//
Label>END2
MDL> Done Sorting %Amount% Items
Phil Pendlebury - Linktree

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts