Home > other >  Linq Lowest Unique Value or Lowest Row and Column Value Whichever Exact match or Partial Match Which
Linq Lowest Unique Value or Lowest Row and Column Value Whichever Exact match or Partial Match Which

Time:10-25

Hello I'm trying to develop a Linq query to find the Lowest Unique Value or Lowest Value also sorted by Row and Column Value.
First it does the Lowest Unique Value Exact match (unique value)
If nothing is found then it does a Partial Match (lowest value then lowest row then column)
Whichever has the smallest Value is the output (unique or not found).

Table of Data

Row Column Value
1 1 2
0 2 3
0 2 2

The output should be the last data in the table 0,2,2 since it has the lowest Row and it's a duplicate Value (row 1 and row 0).

if you add Data 2,0,0 (Value of 0) would overrule the duplicate Values (2's).

Row Column Value
1 1 2
0 2 3
0 2 2
2 0 0

   Structure FoundValue
        Dim Value As Short
        Dim Row As Integer
        Dim Column As Integer
    End Structure
  
   Dim UniqueValuesFound As New List(Of Short)
   Dim ValuesFoundInPath As New List(Of FoundValue)

   UniqueValuesFound.Add(0)
   UniqueValuesFound.Add(2)
   UniqueValuesFound.Add(3)

   Dim foundValue As New FoundValue
   foundValue.Value = 2
   foundValue.Row = 1
   foundValue.Column = 1
   ValuesFoundInPath.Add(foundValue)

   foundValue = New FoundValue
   foundValue.Value = 3
   foundValue.Row = 0
   foundValue.Column = 2
   ValuesFoundInPath.Add(foundValue)

   foundValue = New FoundValue
   foundValue.Value = 2
   foundValue.Row = 0
   foundValue.Column = 2
   ValuesFoundInPath.Add(foundValue)

   'foundValue = New FoundValue
   'foundValue.Value = 0
   'foundValue.Row = 2
   'foundValue.Column = 0
   'ValuesFoundInPath.Add(foundValue)

'New Attempt
    Dim alreadyFound As Boolean = False

    Dim matching = ValuesFoundInPath.Where(Function(s)
                                               Dim index As Integer = UniqueValuesFound.BinarySearch(s.Value)
                                               If alreadyFound = False AndAlso index >= 0 Then
                                                   alreadyFound = True
                                                   Return True 'UniqueValuesFound(index) 'exact match
                                               ElseIf alreadyFound = False AndAlso index < 0 Then
                                                   alreadyFound = True
                                                   Return True 's.Value
                                               Else
                                                   Return False
                                               End If
                                           End Function).OrderBy(Function(p) p.Value).ThenBy(Function(p) p.Row).ThenBy(Function(p) p.Column)
    'New Attempt
        Dim alreadyFound As Boolean = False

        Dim matching = ValuesFoundInPath.Where(Function(s)
                                                   Dim index As Integer = UniqueValuesFound.BinarySearch(s.Value)
                                                   If alreadyFound = False AndAlso index >= 0 Then
                                                       alreadyFound = True
                                                       Return True 'UniqueValuesFound(index) 'exact match
                                                   ElseIf alreadyFound = False AndAlso index < 0 Then
                                                       alreadyFound = True
                                                       Return True 's.Value
                                                   Else
                                                       Return False
                                                   End If
                                               End Function).OrderBy(Function(p) p.Value).ThenBy(Function(p) p.Row).ThenBy(Function(p) p.Column)

Look at 'New Attempt code it speaks itself, what I'm trying to do is find the first value which has a exact match in UniqueValuesFound and if it cannot find the value in UniqueValuesFound array then default to spitting out a partial match lowest value it can find. The array ValuesFoundInPath contains all the values in a random order as well as Column and Row types, which have to be sorted for partial match to find the lowest Row first.

CodePudding user response:

I have finally Solved It!, needed to use Find instead of Where and problem disappeared!.

The answer now requires 2 linq queries instead of one cannot do chaining on Find

    ValuesFoundInPath = ValuesFoundInPath.OrderBy(Function(p) p.Value).ThenBy(Function(p) p.Row).ThenBy(Function(p) p.Column).ToList()

    Dim alreadyFound As Boolean = False

    Dim matching = ValuesFoundInPath.Find(Function(s)
                                              Dim index As Integer = UniqueValuesFound.BinarySearch(s.Value)
                                              If alreadyFound = False AndAlso index >= 0 Then
                                                  alreadyFound = True
                                                  Return True 'UniqueValuesFound(index) 'exact match
                                              ElseIf alreadyFound = False AndAlso index < 0 Then
                                                  alreadyFound = True
                                                  Return True 's.Value
                                              Else
                                                  Return False
                                              End If
                                          End Function)

    Dim result As New Result
    result.Answer = matching.Value
    result.CurrentRow = matching.Row
    result.CurrentColumn = matching.Column

You may have problems since Find(...) pre-sorts the list of values always. So you need to use FindIndex(...) this avoids the sorting issue.

    Dim matchingIndex = ValuesFoundInPath.FindIndex(Function(s)
                                                        Dim index As Integer = UniqueValuesFound.BinarySearch(s.Value)
                                                        If alreadyFound = False AndAlso index >= 0 Then
                                                            alreadyFound = True
                                                            Return True 'UniqueValuesFound(index) 'exact match
                                                        ElseIf alreadyFound = False AndAlso index < 0 Then
                                                            alreadyFound = True
                                                            Return True 's.Value
                                                        End If
                                                        Return False 'No match.
                                                    End Function)

    If matchingIndex < 0 Then MessageBox.Show("Wtf!")

    Dim result As New Result
    result.Answer = ValuesFoundInPath(matchingIndex).Value
    result.CurrentRow = ValuesFoundInPath(matchingIndex).Row
    result.CurrentColumn = ValuesFoundInPath(matchingIndex).Column

It makes the OrderBy(...) useless because Find(...) pre-sorts the lists by incrementing values.

  • Related