Need an example that uses "Array.Find" to retrieve a value in a 2-dimensional array.

I have a collection of generic objects, each containing two properties -- ID and Name. The ID is populated, but the Name is not. Furthermore, I have a separate array that contains all ID-Name matches (it is a two dimensional array). I want to fill each Name property in each generic object using this array and the "Array.Find" method. Note that the "Find" method in "Array.Find" requires a predicate. I've seen multiple examples of this approach working with single-dimensional arrays; however, I've yet to come across any examples of how this is done with a 2-dimensional array.

I can loop through both the generics and the array to accomplish this but I really want to do it using the "Array.Find" approach.

Thanks in advance.
LVL 15
David L. HansenProgrammer AnalystAsked:
Who is Participating?
 
Fernando SotoRetiredCommented:
Hi David;

This is a Linq to Object solution that will do what you need.

'' The Array as you have defined in your question
Dim myArray As String(,) = {{"1", "DO"}, {"2", "RA"}, {"3", "ME"}, {"4", "FA"}}
'' Generic List definition not shown in question. PLEASE NOTE the Name property must be an empty string.
Dim myGenericObjects As New List(Of GenericObject) From {{New GenericObject() With {.ID = "2", .Name = ""}},
                                                         {New GenericObject() With {.ID = "4", .Name = ""}},
                                                         {New GenericObject() With {.ID = "1", .Name = ""}}}

'' The range variable is used to index into the array. 
Dim range = Enumerable.Range(0, myArray.GetLength(0))
'' Iterate through the generic collection finding the array element that matches and then getting the name value
'' and returning both
Dim results = (From mgo In myGenericObjects        
               From idx In range                   
               Where mgo.ID = myArray(idx, 0)      
               Let name = myArray(idx, 1)          
               Select mgo, name).ToList()          

'' Iterating through the results and updating the name in each object.                                                   
For Each obj In results                            
    obj.mgo.Name = obj.name                        
Next

'' At this point myGenericObjects List has been updated with the names and it can be used.

Open in new window

0
 
Fernando SotoRetiredCommented:
The Array.Find works on a Array of 1 dimension as stated in the documentation

From Microsoft Documentation for Array.Find
array
Type: T()
The one-dimensional, zero-based array to search.
0
 
CodeCruiserCommented:
Datatable would make more sense to store this type of data (unless its a school type exercise).
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
sarabandeCommented:
unfortunately a 2-dimensional Array in .NET cannot be treated as 1-dimensional array as it would work in C or C++. instead it is actually an array of 1-dimensional arrays. because of that you only can use the Find for each inner array in a loop.

as the elements of the inner arrays contain of two members, the predicate cannot deduced automatically. you need to pass 'AddressOf predicate', where predicate is a delegate function which would find your elements by the ID only and don't care for Name attribute.

the function would look similar to (bear with me if something is wrong, since i am not a vb programmer)

' This method implements the test condition for the Find
    ' method.
    Private Shared Function CompareID(ByVal search As MyIDNamePair) As Boolean
        If search.ID == ID Then
            Return True
        Else
            Return False
        End If
    End Function

Open in new window


Sara
0
 
Fernando SotoRetiredCommented:
Hi David;

Can you please post the declarations for the generic collection and the array?

Thanks
0
 
David L. HansenProgrammer AnalystAuthor Commented:
Sure Fernando...here it is below.

Sara, Your approach reminds me of this "wordToFind" post where the value to match is set before the array.find kicks off. In that example the array is still a 1-dimensional array; however, I think I've gotten closest to the answer using that example as a guide.

Feel free to post in C#, that's not a difficulty.

Here is a simplified version (all aspects of the original question are represented):
Dim MusicID As String = String.Empty 'declared globally

'--------------------------

Private Sub TestArrayFind()
  Dim myArray As String(,) = {{"1", "DO"}, {"2", "RA"}, {"3", "ME"}, {"4", "FA"}}
  Dim loopIndex As Int32 = 1 'initialize

  Do Until loopIndex > 4
      MusicID = loopIndex.ToString
      MessageBox.Show(Array.Find(myArray, Function(loopIndex) loopIndex.ToString = MusicID)) 'was hoping to have this at least return the string "id" from the array.
      inx += 1
  Loop
End Sub

Open in new window


Now that I look at this again, I think I may have to settle for "array.findindex" the result of which I'll use to directly pull the second column value from the array's row using that index.

I'm beginning to see why there seems to be so few examples of array.find available. Doing brute force matching is about as time consuming (or faster) and is likely far more readable. I'm not even sure there is a performance benefit because arrays are of, the slower, reference-type even when holding value-type data (if I'm not mistaken). If any of you are of a mind to comment on this point, I'd really like to hear each of your views.
0
 
sarabandeCommented:
hmmm.

actually the array you posted was a 1-dimensional array with 4 elements. each element is a pair of two strings, ID and NAME.

since it is 1-dimensional, you can apply the find function directly for the array and a loop is not necessary.

so the working code should be similar to (unfortunately i am neither a vb nor a c# programmer)

Dim MusicID As String = "2" 'declared globally

'--------------------------

Private Sub TestArrayFind()
  Dim myArray As String(,) = {{"1", "DO"}, {"2", "RA"}, {"3", "ME"}, {"4", "FA"}}
  Dim mySearch As String = {MusicID, ""}
  Dim myResult as String =myArray.Find(mySearch, AddressOf IsFirstString);
  MessageBox.Show(myResult(2), ....);  // show the name
End Sub

Open in new window


the 'IsFirstString' delegate function should make a string compare on the first items of a two-item string array.

i don't know whether it is allowed to define function delegates for a generic pair of strings. if not, you may consider to using a helper class for the pair.

Sara
0
 
David L. HansenProgrammer AnalystAuthor Commented:
Thanks everybody, I appreciate your time and patience. And Fernando, you always seem to come through when we need you...gracias!

I actually got two approaches to work and I finally understand Predicates (which was the true point to all of this...no longer are they a mystery).

So here they are, however I never got the array.find to work. Sarabande, I think the system still interprets myArray as two-dimensional. At least through the datatable's "Where" function, I was still able to tackle predicates (as seen below):

Public Sub AssignNamesUsingDataTable(ByVal iDT As DataTable)
	Dim searchID As String = String.Empty
	Dim results As IEnumerable(Of DataRow)

	For Each myGenObj As myGeneric In Me
		searchID = myGenObj.theId
		results = iDT.Select.Where(Function(p) p.Field(Of String)("ID") = searchID.ToString)
		myGenObj.Name = results(0)(1).ToString 'The first column of row(0) in result's datarow is ID, the second column is Name
	Next
End Sub

Public Sub AssignNamesUsingLinq()
	' The range variable is used to index the array. 
	Dim range = Enumerable.Range(0, Me._myArray.GetLength(0))

	' Iterate through the generic collection finding the array element that matches and then getting the Name value and returning both
	Dim results = (From myGenObj In Me
				   From idx In range
				   Where myGenObj.theID = Me._myArray(idx, 0)
				   Let Name = Me._myArray(idx, 1)
				   Select myGenObj, Name).ToList()

	'Iterating through the results updating the name in each object.                                                   
	For Each obj In results
		obj.myGenObj.Name = obj.Name
	Next
End Sub

Open in new window

0
 
David L. HansenProgrammer AnalystAuthor Commented:
I've added my final post to the selected answers only so others may see all solutions. The first solution listed (the datatable solution) I put together, the second shows how I implemented the Linq suggestion given by Fernando. Points were deservedly awarded in full (with an A rating).
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.