How to get the top 3 elements in an int array using LINQ?
Asked Answered
O

4

15

I have the following array of integers:

int[] array = new int[7] { 1, 3, 5, 2, 8, 6, 4 };

I wrote the following code to get the top 3 elements in the array:

var topThree = (from i in array orderby i descending select i).Take(3);

When I check what's inside the topThree, I find:

{System.Linq.Enumerable.TakeIterator}
count:0

What did I do wrong and how can I correct my code?

Octave answered 23/7, 2009 at 5:25 Comment(1)
The object in topThree is not the results, it is the query. topThree is an object which means "sort the sequence of items in array from highest to lowest and take the first three". That's all it means. It does NOT mean "8, 6, 5". It means the query, not the results. You can demonstrate this by executing the query, then changing the array, and then executing the query again. The query is exactly the same but the results are different.Crossroad
C
29

How did you "check what's inside the topThree"? The easiest way to do so is to print them out:

using System;
using System.Linq;

public class Test
{
    static void Main()        
    {
        int[] array = new int[7] { 1, 3, 5, 2, 8, 6, 4 };
        var topThree = (from i in array 
                        orderby i descending 
                        select i).Take(3);

        foreach (var x in topThree)
        {
            Console.WriteLine(x);
        }
    }
}

Looks okay to me...

There are potentially more efficient ways of finding the top N values than sorting, but this will certainly work. You might want to consider using dot notation for a query which only does one thing:

var topThree = array.OrderByDescending(i => i)
                    .Take(3);
Condescendence answered 23/7, 2009 at 5:29 Comment(4)
i checked it in the QuickWatch. Thanks for making things more clear.Octave
QuickWatch is probably being conservative, trying not to execute code for you unless you really ask it to. The query doesn't actually have the data - it just knows how to get at the data. Fetching the data could be slow, or could have side-effects, so it's a bad idea to show that data in the debugger by default.Condescendence
"There are potentially more efficient ways of finding the top N values than sorting" - Can you provide an example of a more efficient method?Mackle
@TotZam: If you remember the current "top 3" at any time, you can just iterate over the results once, slotting elements into those three places as needed. It would be very fiddly though. My Edulinq implementation would be more efficient than LINQ to Objects too, as it only sorts lazily . (It uses a quicksort, but starts returning items when it's sorted the first chunk, as it were.)Condescendence
S
14

Your code seems fine to me, you maybe want to get the result back to another array?

int[] topThree = array.OrderByDescending(i=> i)
                      .Take(3)
                      .ToArray();
Structure answered 23/7, 2009 at 5:31 Comment(0)
F
4

Its due to the delayed execution of the linq query.

As suggested if you add .ToArray() or .ToList() or similar you will get the correct result.

Formant answered 23/7, 2009 at 5:40 Comment(0)
O
-2
int[] intArray = new int[7] { 1, 3, 5, 2, 8, 6, 4 };            
int ind=0;
var listTop3 = intArray.OrderByDescending(a=>a).Select(itm => new { 
    count = ++ind, value = itm 
}).Where(itm => itm.count < 4);
Operatic answered 29/5, 2013 at 7:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.