0

I have a collection (IList(Of Sample)) of the following class:

Public Class Sample
    Public sampleNum As String
    Public volume As Integer
    Public initial As Single
    Public final As Single
End Class

This collection is filled from a regex that gets passed over a file.

What I want to do is use Linq to generate a collection of these for each unique samplenum using the following conditions.

For each samplenum:

  1. Have the highest volume where the final is greater then one
    • If the sample has multiple records for this volume then pick the one with the the highest final
  2. If the previous step leaves us with no records pick the record with the highest final ignoring volume

I am extremely new to Linq and just can't get my head around this. For now I have solved this using for each's and temporary lists but I am interested in how this would be handled using pure Linq.

Sample Data:

samplenum | volume | initial | final
1         | 50     | 8.47    | 6.87
1         | 300    | 8.93    | 3.15
2         | 5      | 8.28    | 6.48
2         | 10     | 8.18    | 5.63
2         | 5      | 8.33    | 6.63
2         | 10     | 8.26    | 5.58
3         | 1      | 8.31    | 0.75
3         | 5      | 8.19    | 0.03
4         | 50     | 8.28    | 6.55
4         | 300    | 7.19    | 0.03

2 Answers 2

1

This should hopefully solve your problems:

    Dim source As IEnumerable(Of Sample)

    ' Get the data... 

    Dim processed = source _
                    .GroupBy(Function(s) s.sampleNum) _
                    .Select(Function(s) Process(s))

    Dim array = processed.ToArray()
    Console.ReadLine()

The Process function:

Private Function Process(ByVal sequence As IEnumerable(Of Sample)) As Sample 
    Dim filtered = (
        From s In sequence
        Where s.final > 1
        Order By
            s.volume Descending,
            s.final Descending
        )

    ' If we don't have any elements after the filtering, 
    ' return the one with the highest final.
    ' Otherwise, return the first element.
    If Not filtered.Any() Then
        Return (From s In sequence Order By s.final Descending).FirstOrDefault()
    Else
        Return filtered.First()
    End If

End Function
Sign up to request clarification or add additional context in comments.

1 Comment

Although both solutions do infact work, this one seems to be alot cleaner. I actually learned a bit about Linq from these.
1

Try this. I haven't tried it but it should do what you want. There is probs a better way of doing this:

    ' For each sample number in the list
    For Each el In (From p In lst Select p.sampleNum).Distinct()
        ' can cause odd results in some cases so always put the foreach var into another var
        Dim var As String = el
        ' get another "list" but for this sample num
        Dim res As IEnumerable(Of Sample) = lst.Where(Function(p) p.volume > 1 AndAlso p.sampleNum = var)
        Dim sam As Sample ' the result
        If Not res Is Nothing And res.Any() Then
            ' we have a result, so get the first result where the 
            sam = res.Where(Function(p) p.volume = res.Max(Function(x) x.volume)).First()
        Else
            ' we have no results, so resort back to the normal list, for this sample number
            sam = lst.Where(Function(p) p.sampleNum = var AndAlso p.volume = lst.Max(Function(x) x.volume)).First()
        End If
        '
        ' do what ever with the sample here
        '
    Next

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.