Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Delete a row from array - HOW-TO?

Status
Not open for further replies.

IlyaRabyy

Programmer
Nov 9, 2010
568
US
Colleagues,
Say, you need to remove some row from an array, like, Row #7 in a String Array(20, 3).
I tried to find some built in function/method in VS 2019 documentation - found nothing.
So, which is it:
a) I just didn't formulate my search criteria correctly,

OR

b) there ain't no such function, and I have to "roll-er-own"?

Please advise!
TIA!

Regards,

Ilya
 
Nope, Arrayus do not have a remove method, so yes, you have to roll your own.

They do however have methods that perhaps make this easier than a traditional looping solution. Have a look at the Copy (and Clear) methods
 
[Sigh!]
Yeah, I did look them up, found them not so much inspiring...
Ah, well, "Man's gotta do what man's gotta do" - rite? :)

Regards,

Ilya
 
>not so much inspiring...

Really?

Here's an example of how you might do it (note it is just an example to illustrate the idea, not a robust solution)

Code:
[COLOR=blue]Private Function removearrayrow(rownum As Integer, SourceArray As Array) As Array
        Dim ElementsInRow As Integer = SourceArray.GetLength(1)
        Dim startelement As Integer = rownum * ElementsInRow
        Dim lastelement As Integer = SourceArray.Length
        Dim DestinationArray(UBound(SourceArray, 1) - 1, UBound(SourceArray, 2))  [COLOR=green]' 1 fewer rows in destination array[/color]

        Array.Copy(SourceArray, 0, DestinationArray, 0, startelement) [COLOR=green]' copy up to deletion point[/color]
        Array.Copy(SourceArray, startelement + ElementsInRow, DestinationArray, startelement, lastelement - startelement - ElementsInRow) [COLOR=green]' copy after deletion point[/color]

        removearrayrow = DestinationArray
End Function[/color]

and you might callit like:

Code:
[COLOR=blue]        Dim myarray = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} ', {13, 14, 15, 16}}
        Dim destArray = removearrayrow(1, myarray)[/color]

 
Maybe an array is the wrong choice, maybe what you actually need is a Collection [ponder]

Just a guess here since we do not know what you are trying to accomplish...

---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
Andy, that was going to be my next post: Is an array actually the best choice here?
 
Andrzejek said:
maybe what you actually need is a Collection [ponder]

I'm dealing with 2-dim arrays, all elements are of the same data type. And these arrays are filled in by reading CSV files, for example - Federal Tax rates chart:

TaxRate,BracketFrom,BracketTo
10,0,11000
12,11001,44725
22,44726,95375
24,95376,182100
32,182101,231250
35,231251,578125
37,578126,100000000

Now, dealing with Zero-Based stuff is a headache in its own, and when you get something like the above in XLS, and convert it into CSV, there is this header row... and you have to juggle zero-based counts with 1-based ones... then it becomes royal headache!
Hence the want to delete this header row sprang, and then the idea to have a generic function/sub if there's no such thing built-in in VB and/or .NET.

So, I'm not sure how Collection can help in such situation.

Regards,

Ilya
 
these arrays are filled in by reading CSV files"... "there is this header row..."
Just ignore 'this header row' when you populate your array.
[pre]
TaxRate BracketFrom BracketTo

10 0 11000
12 11001 44725
22 44726 95375
24 95376 182100
32 182101 231250
35 231251 578125
37 578126 100000000[/pre]

Looks like a very simple, very small table in a data base....

---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
Ilya said:
these arrays are filled in by reading CSV files
Show your code where/how you do it. I am sure there is an easy way to read your CSV starting from 2nd record / line of text.

---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
Andrzejek said:
Show your code where/how you do it.

"Per popular demand" ( :) )

Code:
'====================================================================================================================================
Public Sub Populate2DimArrayFromCSV(ByVal tsFileCSV, ByRef taRes)
'====================================================================================================================================
' Purpose       : Populates the given 2-dimensional array off the read CSV file.
' Description   : Reads the given CSV file into a 1-dimentional String array, then creates a 2-dimensional array and fills out its
'		  elements with the data read from the 1-dimensional one.
' Parameters	: Full path to the CSV file
'		   Pointer on the 2-dimensional array to populate
' Returns	: N/A
' Side effects  : If the parameter array was populated, its contents is overwritten.
' Notes         : 1. Generic for the applications having this module's Str_Extract() function.
'                 2. Complies with .NET Framework ver. 1.1 and higher.
'		  3. The 1st row in the CSV is presumed containing the columns' names.
' Author        : Ilya I. Rabyy
' Revisions     : by Ilya on 2022-09-08 - finished 1st draft.
'		  by Ilya on 2023-04-20 to replace the hardcoded number of columns with that calculated above.
'====================================================================================================================================
Dim laData() As String = File.ReadAllLines(tsFileCSV), lcFld As String = ""
Dim liRows As Integer = laData.GetLength(0), liCols As Integer = GetChrCount(",", laData(0))

'************************************************************************************************************************************
'******** Next code was modified by Ilya on 2023-04-20 to replace the hardcoded number of columns with that calculated above ********
'Dim laTable(liRows - 1, 9) As String
Dim laTable(liRows - 1, liCols) As String
'********* End of code modified by Ilya on 2023-04-20 to replace the hardcoded number of columns with that calculated above *********
'************************************************************************************************************************************

For I As Integer = 0 To liRows - 1 ' 1st row - columns' names
	For J As Integer = 0 To liCols
		If J = 0 Then
			lcFld = Str_Extract(laData(I), "", ",")
		ElseIf J = liCols Then
			lcFld = Str_Extract(laData(I), ",", "", J)
		Else
			lcFld = Str_Extract(laData(I), ",", ",", J)
		End If

		laTable(I, J) = lcFld
	Next
Next

ReDim taRes(liRows - 1, liCols)
taRes = laTable

End Sub
'====================================================================================================================================

The thing is, since it's a Public proc (in the module being included into other projects) and, thus, can be used in any program, I don't know whether that latter has to read CSV which has, or has no, this header row... Not to mention that the need may arise to remove a row somewhere in the middle of a set...
IOW, I'm aiming to make a proc for removing a row in an array as generic as humanly possible (and then some :) )!

Regards,

Ilya
 
I would love to try it, but [tt]GetChrCount[/tt] and [tt]Str_Extract[/tt] are not declared. :-(
Or I am missing something...

---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
Anywho, just a guess here...

Code:
Public Sub Populate2DimArrayFromCSV(ByVal tsFileCSV, ByRef taRes[blue], Optional blnIgnoreHeaderRow As Boolean = False[/blue])
...
        For I As Integer = 0 To liRows - 1 [green]' 1st row - columns' names[/green][blue]
            If blnIgnoreHeaderRow Then
                blnIgnoreHeaderRow = False
            Else[/blue]
                For J As Integer = 0 To liCols
                    If J = 0 Then
                        lcFld = Str_Extract(laData(I), "", ",")
                    ElseIf J = liCols Then
                        lcFld = Str_Extract(laData(I), ",", "", J)
                    Else
                        lcFld = Str_Extract(laData(I), ",", ",", J)
                    End If

                    laTable(I, J) = lcFld
                Next[blue]
            End If[/blue]
        Next
...

---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
Andrzejek said:
I would love to try it, but GetChrCount and Str_Extract are not declared

But of course!... Errr... Mea culpa! Here they are

Code:
'====================================================================================================================================
Public Function Str_Extract(ByVal tsSrcString As String, ByVal tsBegDelim As String, ByVal tsEndDelim As String, _
								Optional ByVal tiOccurance As Integer = 1, Optional ByVal tiFlag As Integer = 0, _
								Optional ByVal tlAddDelims As Boolean = False) As String
'====================================================================================================================================
' Purpose       : Extracts a substring from the given string.
' Description   : Essentially, a "replica" of the VFP's built-in STREXTRACT() function.
'                 Calculates starting position and length of the substring to be extracted based on starting positions and lengths
'                 of the given starting and ending delimiters, applying the CompareMethod. Then uses the VB's built-in Mid() function
'                 for string extraction.
' Returns       : Extracted substring as String.
'                 If the given Source string is empty - returns empty string.
'                 If the starting delimiter is empty String - extracts the left part of the given string till the starting position
'                    of the ending delimiter.
'                 If the ending delimiter is empty String - extracts the right part of the given string beginning on the ending 
'                    position of the starting delimiter.
'                 If both starting and ending delimiters are empty strings - returns the entire given source string.
' Side effects  : None.
' Notes         : 1. Generic.
'                 2. Complies with .NET Framework ver. 1.1 and higher.
'                 3. Verbose on errors, silent otherwise.
'                    format - remains on the calling prog's "conscience".
' Author        : Ilya I. Rabyy
' Revisions     : 2020-06-01 by Ilya – completed 1st draft.
'		  by Ilya on 2022-07-06 to add delimiters into returned string, if requested.
'====================================================================================================================================
Dim lsRetStr As String = ""

' Parameters' verification / validation
' ComparisonMethod flag: can be either 0 (case-sensitive comparison) or 1 (case-insensitive comparison)
If tiFlag > 0 Then
	tiFlag = 1
End If

' Occurance
If tiOccurance <= 0 Then
	Return lsRetStr
End If

' Given Source string
If IsNothing(tsSrcString) Then
	Return lsRetStr
ElseIf tsSrcString.Trim() = "" Then
	Return lsRetStr
End If

Dim liSrcLen As Integer = Len(tsSrcString), liStartPos As Integer = 0, liRetLength As Integer = 0

' Starting and ending delimiters, Starting one's 1st
If IsNothing(tsBegDelim) Then
	liStartPos = 1
ElseIf tsBegDelim = "" Then
	liStartPos = 1
ElseIf tiOccurance > 1 Then
	liStartPos = 1

	For liCnt As Integer = 1 To tiOccurance
		liStartPos = InStr(liStartPos, tsSrcString, tsBegDelim, tiFlag) + Len(tsBegDelim)
	Next 'liCnt
Else
	liStartPos = InStr(1, tsSrcString, tsBegDelim, tiFlag) ' + Len(tsBegDelim)
	' Since the given starting delimiter might not be found...
	If liStartPos = 0 Then
		Return lsRetStr
	Else
		liStartPos = liStartPos + Len(tsBegDelim)
	End If ' liStartPos = 0
End If 'IsNothing(tsBegDelim)

' Ending delimiter
If IsNothing(tsEndDelim) Then
	liRetLength = liSrcLen - liStartPos + 1
ElseIf tsEndDelim = "" Then
	liRetLength = liSrcLen - liStartPos + 1
ElseIf InStr(1, tsSrcString, tsEndDelim, tiFlag) = 0 Then
	Return lsRetStr
Else
   liRetLength = InStr(liStartPos, tsSrcString, tsEndDelim, tiFlag) - liStartPos
   liRetLength = InStr(liStartPos + 1, tsSrcString, tsEndDelim, tiFlag) - liStartPos
End If 'IsNothing(tsEndDelim)

' If we came to this point - everything's kosher, we can extract the string
lsRetStr = Mid(tsSrcString, liStartPos, liRetLength)
'************************************************************************************************************************************
'****************** Next code was added by Ilya on 2022-07-06 to add delimiters into returned string, if requested ******************
If tlAddDelims Then
	lsRetStr = tsBegDelim & lsRetStr & tsEndDelim
End If
'******************* End of code added by Ilya on 2022-07-06 to add delimiters into returned string, if requested *******************
'************************************************************************************************************************************

Return lsRetStr

End Function
'====================================================================================================================================

'====================================================================================================================================
Public Function GetChrCount(Optional ByVal tcChar As String = "", Optional ByVal tcStr As String = "", _
								Optional tlCaseSensitive As Boolean = False) As Integer
'====================================================================================================================================
' Purpose       : Counts the occurances of the given Character in the given String.
' Description   : If any of the two optional parameters is blank - returns zero.
'                 Goes char-by-char through the given parameter-string counting given char parameter's occurances.
' Parameters    : Sought Character as String;
'                 Searched string as String.
' Returns       : Number of occurances of the given Character in the given String.
' Side effects  : None.
' Notes         : 1. Generic, applies to .NET Framework ver. 1.1, .NET Core 1.0, .NET Standard 1.0 and higher.
'                 2. Silent.
'                 3. If tcChar contains more than one character - it's truncated to the 1st one.
' Author        : Ilya I. Rabyy
' Revisions     : 2020-08-13 by Ilya – started 1st draft.
'		  2022-02-04 by Ilya - made standard one.
'		  2022-02-15 by Ilya - section was added to check if the given String contains the sought Char at all.
'====================================================================================================================================
Dim lnRet As Integer = 0

' Parameters' validation
If tcChar = "" Or tcStr = "" Then
	MsgBox("Blank String(s) argument(s) aren't allowed!", MsgBoxStyle.Information, "Function GetChrCount(): invalid parameter(s)")
	Return lnRet
End If

If Len(tcChar) > 1 Then
	tcChar = Left(tcChar, 1)
End If

'************************************************************************************************************************************
'************ Next section was added by Ilya on 2022-02-15 to check if the given String contains the sought Char at all *************
If Not tcStr.Contains(tcChar) Then Return lnRet
'************** End of section added by Ilya on 2022-02-15 to check if the given String contains the sought Char at all *************
'************************************************************************************************************************************

Dim lcChar As String, liCnt As Integer

For liCnt = 1 To Len(tcStr)
	lcChar = Mid(tcStr, liCnt, 1)
	lcChar = IIf(tlCaseSensitive, lcChar, lcChar.ToUpper())

	If lcChar = tcChar.ToUpper() Then
		lnRet += 1
	End If
Next liCnt

Return lnRet
End Function
'====================================================================================================================================

Regards,

Ilya
 
>I'm aiming to make a proc for removing a row in an array

Which I think you'll find my earlier example achieves despite your lack of enthusiasm for Copy

As for reading from a CSV, I'd be tempted to use a TextFieldParser (and for the particular case where you are later removing the first 'row' of the array to eliminate the header, just skip the header when originally reading the CSV, as per Andy's suggestion)
 
just skip the header when originally reading the CSV", a simple example.
I'm sure you can easily add some code to populate your array

Code:
    Public Sub ReadCSVLineByLine(ByVal tsFileCSV As String, [blue]Optional blnIgnoreHeaderRow As Boolean = False[/blue])
        Dim FILE_NAME As String = tsFileCSV
        Dim TextLine As String
        Dim strTemp As String

        If System.IO.File.Exists(FILE_NAME) = True Then
            Dim objReader As New System.IO.StreamReader(FILE_NAME)
            Do While objReader.Peek() <> -1
                If blnIgnoreHeaderRow Then
                    strTemp = objReader.ReadLine()  [green]'just ignore it[/green]
                    blnIgnoreHeaderRow = False
                End If
                TextLine = TextLine & objReader.ReadLine() & vbNewLine
            Loop
            MessageBox.Show(TextLine)
        Else
            MessageBox.Show("File " & tsFileCSV & " Does Not Exist")
        End If
    End Sub

I cheated with strTemp


---- Andy

"Hmm...they have the internet on computers now"--Homer Simpson
 
So, StreamReader instead of ReadAllLines?
Hmmm...

Regards,

Ilya
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top