ritesh khadka
ritesh khadka

Reputation: 152

How to get value from matching key from keyvalue pair list in vb.net using linq?

I want to have the value from keyvalue pair list which key matches the given data. I have data in list as follows

LeftExistingLayerName
(0)=>{[data1, 0.04#0]}
(1)=>{[data2, 0.04#0]}
(2)=>{[data3, 0.04#0]}

I have used following code to get the single value e.g matching data1

Dim LeftExistingLayerName As List(Of KeyValuePair(Of String, String)) = New List(Of KeyValuePair(Of String, String))
Dim result As String()
If LeftExistingLayerName.Where(Function(x) x.Key.Contains(g.LayerName)).Any() Then
Dim result1 = LeftExistingLayerName _                                                             
              .Where(Function(x) x.Key.Contains(g.LayerName)) _                                               
              .Select(Function(x) x.Value) _
             .ToString()
result = result1.Split(New String() {"#"}, StringSplitOptions.None)
End If

I want to have the value in the string reslut1 and split "#" and take out the values 0.04 in result(0) and 0 in result1
I am getting this error

Conversion from string "System.Linq.Enumerable+WhereSele" to type 'Double' is not valid

Upvotes: 2

Views: 1675

Answers (1)

Ousmane D.
Ousmane D.

Reputation: 56433

You're not showing the code that is causing the problem as the error states there was an issue when "attempting to convert a string to a double". Nothing in your code illustrates this.

Anyhow, to the point...

The string "System.Linq.Enumerable+WhereSele" is clearly not what you want to convert to a double value. The string representation comes from the fact that you're invoking ToString() on an Enumerable returned from the Select clause then trying to convert that to a double.

Given you've said that:

I have used following code to get the single value e.g matching data1

We can agree that you're expecting a single value back from the Enumerable query, As @jmcilhinney has suggested in the comments there are various methods that do this for you each of which are made for a specific scenario.

i.e.

  • First
  • FirstOrDefault
  • Single
  • SingleOrDefault

I'll let you investigate the little details that differentiate them, but for now and for example purposes you can use FirstOrDefault.

So, your code becomes:

Dim result As String = LeftExistingLayerName _                                                             
              .Where(Function(x) x.Key.Contains(g.LayerName)) _                                               
              .Select(Function(x) x.Value) _
              .FirstOrDefault()

reads as "return the first value of the KeyValuePair where the KeyValuePair's key contains g.LayerName otherwise the default value of a reference type"

So, at this point, we can then split the string by the delimiter "#" and covert the first, second items of the array to a double or any other type.

Dim array As String() = LeftExistingLayerName _                                                             
                  .Where(Function(x) x.Key.Contains(g.LayerName)) _                                               
                  .Select(Function(x) x.Value) _
                  .FirstOrDefault() _
                  .Split(New String() {"#"}, StringSplitOptions.None)
   ' array(0) gets the 0.04 part of your example
   ' array(1) gets the 0 part of your example

This should suffice as long as the predicate Function(x) x.Key.Contains(s) is always guaranteed to be met. Otherwise, you'll get a NullReferenceException upon invoking .Split on a null reference returned by FirstOrDefault.

If you want to handle that scenario then you can use the null propagation operator (?).

Dim array As String() = LeftExistingLayerName _                                                             
                      .Where(Function(x) x.Key.Contains(g.LayerName)) _                                               
                      .Select(Function(x) x.Value) _
                      .FirstOrDefault() _
                      ?.Split(New String() {"#"}, StringSplitOptions.None)

Btw, you can simplify:

If LeftExistingLayerName.Where(Function(x) x.Key.Contains(g.LayerName)).Any() Then

to:

If LeftExistingLayerName.Any(Function(x) x.Key.Contains(g.LayerName)) Then

Upvotes: 2

Related Questions