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. HansenCEOAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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
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
Big Business Goals? Which KPIs Will Help You

The most successful MSPs rely on metrics – known as key performance indicators (KPIs) – for making informed decisions that help their businesses thrive, rather than just survive. This eBook provides an overview of the most important KPIs used by top MSPs.

Fernando SotoRetiredCommented:
Hi David;

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

Thanks
0
David L. HansenCEOAuthor 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
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
David L. HansenCEOAuthor 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. HansenCEOAuthor 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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.