Jump to content

Recommended Posts

Posted (edited)

I import CSV files which have various headers.
Is there a way to simply keep only the ones I need and in the order I need them in?
For example, if the array's first row's values are Foo Bar Test This, then I want to turn them to Foo This Bar.
Here's how I do it "manually" with _ArrayColDelete and _ArraySwap, but I want to use something smarter like rearrange($aArray, ["Foo", "This", "Bar"]):

#include <Array.au3>

Local $aArray[4][4] = [["Foo", "Bar", "Test", "This"], [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
_ArrayDisplay($aArray, "Original")
_ArrayColDelete($aArray, 2) ;2 stands for Test, but next time Test might not be 2, but it will still be called "Test"
_ArraySwap($aArray, 1, 2, true) ;1 and 2 might be different next time, but their names will remain
_ArrayDisplay($aArray, "Modified")

If it helps, I do the same thing in VBA based on Sub Reorganize_columns  (the second/alternative example in that page).

Edited by LWC
Removed the Solved from title now that it's automated
Posted

Hasn't been thoroughly tested but maybe something like this:

#include <Array.au3>

Local $aArray[4][4] = [["Foo", "Bar", "Test", "This"], [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
_ArrayDisplay($aArray, "Original")

Local $aRange[3] = ["Foo", "This", "Bar"]
$aArray = _ReArrange($aArray,  $aRange)

Func _ReArrange($aSearch, $aRange)
    Local $iSearch
    For $i = UBound($aSearch, 2) - 1 To 0 Step - 1
        $iSearch = _ArraySearch($aRange, $aSearch[0][$i])
        If $iSearch > -1 Then
            If $i <> $iSearch Then _ArraySwap($aSearch, $iSearch, $i, True)
        EndIf
        If $iSearch = -1 Then
            _ArrayColDelete($aSearch, $i)
            ContinueLoop
        EndIf
    Next
    Return $aSearch
EndFunc

_ArrayDisplay($aArray, "Modified")

 

Posted (edited)

another one:

#include <Array.au3>

Local $aArray[5][4] = [["Foo", "Bar", "Test", "This"],[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]]
_ArrayDisplay($aArray, "Original")

Local $aWanted[] = ["Foo", "This", "Bar"]
Local $aModified = rearrange($aArray, $aWanted)

_ArrayDisplay($aModified, "Modified")


Func rearrange(ByRef $aArray, ByRef $aIndex)

    Local $aResult[UBound($aArray)][UBound($aIndex)]
    Local $aNdx[UBound($aIndex)]

    For $i = 0 To UBound($aIndex) - 1
        For $x = 0 To UBound($aArray, 2) - 1
            If $aArray[0][$x] = $aIndex[$i] Then
                $aNdx[$i] = $x
                ExitLoop
            EndIf
        Next
    Next

    For $i = 0 To UBound($aArray) - 1
        For $x = 0 To UBound($aIndex) - 1
            $aResult[$i][$x] = $aArray[$i][$aNdx[$x]]
        Next
    Next
    Return $aResult
EndFunc   ;==>rearrange

 

Edited by Chimp
little debug

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Posted (edited)

@Chimp A perfectly good method which answers the question, but I think that passing the desired numeric sequence of columns would be better than passing an array of headers. The reason is that some headers may be duplicated, or omitted. Just a passing comment: in case it might be relevant to LWC (or anyone else).

Edited by czardas
Posted (edited)

Hi @czardas, I agree with you,

in post #3 I've verbatim answered to the OP's request.

@LWC If you mind to pass the numbers of the desired columns instead of their names, the function is even simpler (and bulletproof ...)

#include <Array.au3> ; just for _ArrayDisplay

Local $aArray[5][4] = [["Foo", "Bar", "Test", "This"],[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]]
_ArrayDisplay($aArray, "Original")

; pass columns number instead of names
Local $aWanted[] = [0, 3, 2] ; first column is number 0 (zero based)
Local $aModified = rearrange($aArray, $aWanted)

_ArrayDisplay($aModified, "Modified")

Func rearrange(ByRef $aArray, ByRef $aIndex)

    Local $aResult[UBound($aArray)][UBound($aIndex)] ; build the output array

    For $i = 0 To UBound($aArray) - 1 ; fill it with desired data
        For $x = 0 To UBound($aIndex) - 1
            $aResult[$i][$x] = $aArray[$i][$aIndex[$x]]
        Next
    Next

    Return $aResult
EndFunc   ;==>rearrange

 

Edited by Chimp
specified script's addressee

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Posted

@Chimp's right that I asked for header names, as they're less dynamic then column locations.

But no one addressed @Subz' code.

Assuming the consensus favors Chimp's code, here's a variation that supports both non 0-based arrays and quoted/chr(34) headers (due to the linked function that imports CSV files in my OP):

#include <Array.au3>

Local $aArray[5][4] = [["Foo", "Bar", "Test", "This"],[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]]
_ArrayDisplay($aArray, "Original 0-based")
Local $aWanted[] = ["Foo", "This", "Bar"]
$aArray = rearrange($aArray, $aWanted)
_ArrayDisplay($aArray, "Modified 0-based")

_ArrayInsert($aArray, 0, ubound($aArray)) ; Turns this array into non 0-based
_ArrayDisplay($aArray, "Original non 0-based")
$aArray = rearrange($aArray, $aWanted, false)
_ArrayDisplay($aArray, "Modified non 0-based")

Func rearrange(ByRef $aArray, ByRef $aIndex, $0_based=true)

    local $count
    if not $0_based Then
        $count = $aArray[0][0]
        _ArrayDelete($aArray, 0)
    EndIf
    Local $aResult[UBound($aArray)][UBound($aIndex)]
    Local $aNdx[UBound($aIndex)]

    For $i = 0 To UBound($aIndex) - 1
        For $x = 0 To UBound($aArray, 2) - 1
            If $aArray[0][$x] = $aIndex[$i] or $aArray[0][$x] = chr(34) & $aIndex[$i] & chr(34) Then
                $aNdx[$i] = $x
                ExitLoop
            EndIf
        Next
    Next

    For $i = 0 To UBound($aArray) - 1
        For $x = 0 To UBound($aIndex) - 1
            $aResult[$i][$x] = $aArray[$i][$aNdx[$x]]
        Next
    Next

    if not $0_based Then
        _ArrayInsert($aResult, 0, $count)
    EndIf

    Return $aResult
EndFunc   ;==>rearrange

My last question is, how can I add something like:

Local $aWanted[] = ["Foo", "This", "", "Bar"]

And have the function add a blank column when it sees ""?

Posted

the function will add a blank column when it sees "" (an empty string) or it doesn't found the wanted column name:

#include <Array.au3>

Local $aArray[5][4] = [["Foo", "Bar", "Test", "This"],[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]]
_ArrayDisplay($aArray, "Original 0-based")
Local $aWanted[] = ["Foo", "Dummy", "This", "", "Bar"]
$aModified = rearrange($aArray, $aWanted)
_ArrayDisplay($aModified, "Modified 0-based")

_ArrayInsert($aArray, 0, UBound($aArray)) ; Turns this array into non 0-based
_ArrayDisplay($aArray, "Original non 0-based")
$aModified = rearrange($aArray, $aWanted, False)
_ArrayDisplay($aModified, "Modified non 0-based")

Func rearrange(ByRef $aArray, ByRef $aIndex, $0_based = True)

    Local $count

    If Not $0_based Then
        $count = $aArray[0][0]
        _ArrayDelete($aArray, 0)
    EndIf


    Local $aResult[UBound($aArray)][UBound($aIndex)]
    Local $aNdx[UBound($aIndex)]

    For $i = 0 To UBound($aIndex) - 1
        For $x = 0 To UBound($aArray, 2) - 1
            If $aArray[0][$x] = $aIndex[$i] Then
                $aNdx[$i] = $x
                ExitLoop
            ElseIf $aIndex[$i] = "" Then
                $aNdx[$i] = Null ; an empty column wanted
                ExitLoop
            ElseIf $x = UBound($aArray, 2) - 1 Then
                $aNdx[$i] = Null ; wanted string not found (leave an empty column)
            EndIf
        Next
    Next

    For $i = 0 To UBound($aArray) - 1
        For $x = 0 To UBound($aIndex) - 1
            If $aNdx[$x] <> Null Then
                $aResult[$i][$x] = $aArray[$i][$aNdx[$x]]
            EndIf
        Next
    Next

    If Not $0_based Then
        _ArrayInsert($aResult, 0, $count)
    EndIf

    Return $aResult
EndFunc   ;==>rearrange

 

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

  • Solution
Posted (edited)

Here's again support for quoted headers + plus adding unfound column names instead of using blanks:

#include <Array.au3>

Local $aArray[5][4] = [["""Foo""", "Bar", "Test", "This"],[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]]
_ArrayDisplay($aArray, "Original 0-based")
Local $aWanted[] = ["Foo", "Dummy", "This", "", "Bar"]
$aModified = rearrange($aArray, $aWanted)
_ArrayDisplay($aModified, "Modified 0-based")

_ArrayInsert($aArray, 0, UBound($aArray)) ; Turns this array into non 0-based
_ArrayDisplay($aArray, "Original non 0-based")
$aModified = rearrange($aArray, $aWanted, False)
_ArrayDisplay($aModified, "Modified non 0-based")

Func rearrange(ByRef $aArray, ByRef $aIndex, $0_based = True)

    Local $count

    If Not $0_based Then
        $count = $aArray[0][0]
        _ArrayDelete($aArray, 0)
    EndIf

    Local $aResult[UBound($aArray)][UBound($aIndex)]
    Local $aNdx[UBound($aIndex)]

    For $i = 0 To UBound($aIndex) - 1
        For $x = 0 To UBound($aArray, 2) - 1
            If $aArray[0][$x] = $aIndex[$i] or $aArray[0][$x] = chr(34) & $aIndex[$i] & chr(34) Then
                $aNdx[$i] = $x
                ExitLoop
            ElseIf $aIndex[$i] = "" Then
                $aNdx[$i] = Null ; an empty column wanted
                ExitLoop
            ElseIf $x = UBound($aArray, 2) - 1 Then
                $aNdx[$i] = Null ; wanted string not found (leave an empty column)
            EndIf
        Next
    Next

    For $i = 0 To UBound($aArray) - 1
        For $x = 0 To UBound($aIndex) - 1
            If $aNdx[$x] <> Null Then
                $aResult[$i][$x] = $aArray[$i][$aNdx[$x]]
            elseif $i=0 and $aIndex[$x]<>"" then ; if wanted string not found, use it as a title for the blank column
                $aResult[$i][$x]=$aIndex[$x]
            EndIf
        Next
    Next

    If Not $0_based Then
        _ArrayInsert($aResult, 0, $count)
    EndIf

    Return $aResult
EndFunc   ;==>rearrange

 

Edited by LWC
  • LWC changed the title to Rearrange array columns based on first row's values

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
×
×
  • Create New...