E. A. Bagby
E. A. Bagby

Reputation: 930

Get array of double from list of array of double, where first value in array is the max first value using linq

I want to get the array of doubles from a list of an array of doubles where the first value of the array is the highest value as compared to the first value of the other arrays in the list

For example, if the list of arrays are (4,5) , (-3,2) , (7,1) then it would return (7,1).

I tried this but no success:

Dim vertices as List(of Double()) = MethodToGetList()

dim rv as Double() = vertices.Select(Function(x As Double()) x.First.MaxValue).ToArray

Upvotes: 0

Views: 385

Answers (2)

dvo
dvo

Reputation: 2153

Try this. This orders the vertices list of arrays by the first position of each array, then by the second position of the array. Then in the case of the same data (below), the list would look like: (7,1), (7,2), .... Then last piece of the statement grabs the first element in the sorted list so would return (7, 1)

Dim rv As Double() = vertices.OrderByDescending(Function(v) v(0)).ThenBy(Function(v) v(1)).FirstOrDefault

Data to test:

Dim vertices As List(Of Double()) = New List(Of Double())

vertices.Add(New Double() {4, 5})
vertices.Add(New Double() {-1, 2})
vertices.Add(New Double() {7, 1})
vertices.Add(New Double() {7, 2})

Upvotes: 0

Harald Coppoolse
Harald Coppoolse

Reputation: 30454

Sorry, my basic is a bit rusty, I'll do it in C#, I hope you'll get the gist.

Whenever you want a LINQ function, where you need to examine every item of your sequence exactly once, and you want to do something with the item that is currently being examined, think of Aggregate.

This will initialize variable highestValue with your first source element; then it will compare every source element with the highestValue and keep the one that is highest:

List<List<double>> mySource = ...
var result = mySource.Aggregate( (highestValue, nextValue) =>
    (nextValue[0] > highestValue[0]) ? nextValue : highestValue);

This will be similar to:

List<double> highestValue = mySource[0];
for (int i=1; i<mySource.Count; ++i)
{
    if (mySource[i][0] > higestValue[0])
    {
        // found a new highestValue
        highestValue = mySource[i];
    }
    // else: keep the highest value
}

It is easy to see, that this only works if mySource is not empty. If you have an empty source, you should think of what you want as a result. We will initialize with this emptyResult:

List<double> emptyResult = ... // what do you want to use if there is nothing in your source?

List<double> highestValue = emptyResult;
for (int i=0; i<mySource.Count; ++i)
{
    if (mySource[i][0] > higestValue[0])
    {
        // found a new highestValue
        highestValue = mySource[i];
    }
}

And now in LINQ: use the other Aggregate:

var result = mySource.Aggregate(emptyResult, // use this as seeder
    (nextValue[0] > highestValue[0]) ? nextValue : highestValue);

This will help if you have an empty sequence. Buf what if one of your Lists in the source is null or empty?

Let's assume you don't want to consider them at all:

var nonEmptyArrays = mySource.Where(list => list != null && list.Count != 0)
var result = noneEmptyArrays.Aggregate((emptyResult, // use this as seeder
    (nextValue[0] > highestValue[0]) ? nextValue : highestValue);

Simple comme bonjour!

Upvotes: 1

Related Questions