LINQ help

I have a collection of ints, how can I take the last three that are bigger than 100? is there a better way than this?
using System;
using System.Linq;

class Program
{
static void Main()
{
int[] numbers = { 80, 120, 110, 90, 10, 140, 150, 50, 22, -800 };

var result = numbers.Where(num => num > 100).Reverse().Take(3).Reverse().ToArray();

Console.WriteLine("Last 3 elements over 100:");
foreach (var num in result)
{
Console.WriteLine(num);
}
}
}
using System;
using System.Linq;

class Program
{
static void Main()
{
int[] numbers = { 80, 120, 110, 90, 10, 140, 150, 50, 22, -800 };

var result = numbers.Where(num => num > 100).Reverse().Take(3).Reverse().ToArray();

Console.WriteLine("Last 3 elements over 100:");
foreach (var num in result)
{
Console.WriteLine(num);
}
}
}
17 Replies
Jason_Bjorn
Jason_Bjorn2w ago
reversing the entire numbers array to take the first (last then) 3 seems kinda ineffecient
daniel2
daniel22w ago
I suggest u use for loop reversely
Alex_is_coding
I was curious to try, and got this
int[] numbers = { 80, 120, 110, 90, 10, 140, 150, 50, 22, -800 };

IOrderedEnumerable<int> sortedNum = numbers.OrderDescending();
string aStr = string.Empty;
for(int i = 0; i <= 2; i++)
{
if (sortedNum.ElementAt(i) >= 100)
{
aStr += sortedNum.ElementAt(i).ToString() + "\r\n";
}
}
MessageBox.Show( aStr );
int[] numbers = { 80, 120, 110, 90, 10, 140, 150, 50, 22, -800 };

IOrderedEnumerable<int> sortedNum = numbers.OrderDescending();
string aStr = string.Empty;
for(int i = 0; i <= 2; i++)
{
if (sortedNum.ElementAt(i) >= 100)
{
aStr += sortedNum.ElementAt(i).ToString() + "\r\n";
}
}
MessageBox.Show( aStr );
Jason_Bjorn
Jason_Bjorn2w ago
Why sort them seems like a waste of time? Just traverse in reverse then and pick until you have 3 or reach end (start) like this?
int[] numbers = [80, 120, 110, 90, 10, 140, 150, 50, 22, -800];

int[] threeOver100 = new int[3];
int insertIndex = threeOver100.Length - 1;

for (int i = numbers.Length - 1; i >= 0; i--)
{
if (numbers[i] > 100)
{
threeOver100[insertIndex] = numbers[i];
insertIndex--;
if (insertIndex < 0)
{
break;
}
}
}

Array.ForEach(threeOver100, Console.WriteLine);
int[] numbers = [80, 120, 110, 90, 10, 140, 150, 50, 22, -800];

int[] threeOver100 = new int[3];
int insertIndex = threeOver100.Length - 1;

for (int i = numbers.Length - 1; i >= 0; i--)
{
if (numbers[i] > 100)
{
threeOver100[insertIndex] = numbers[i];
insertIndex--;
if (insertIndex < 0)
{
break;
}
}
}

Array.ForEach(threeOver100, Console.WriteLine);
2spooky2play
2spooky2play2w ago
ForEach really sucks, dont use it
Jason_Bjorn
Jason_Bjorn2w ago
can you elaborate?
2spooky2play
2spooky2play2w ago
the last Reverse().ToArray() seems unnecessary its a long story, but 1) its slower (iirc) 2) it requires an allocated list (sometimes you dont need to allocate) var result = numbers.Where(num => num > 100).Reverse().Take(3) is all you need
Jason_Bjorn
Jason_Bjorn2w ago
but isn't reverse expensive? sound like O(n) more space when I only need O(3) more space
2spooky2play
2spooky2play2w ago
linq is lazy, so i doubt it allocates
Jason_Bjorn
Jason_Bjorn2w ago
any way to know for sure?
2spooky2play
2spooky2play2w ago
ask someone in #advanced maybe?
Jason_Bjorn
Jason_Bjorn2w ago
okay
TheBoxyBear
TheBoxyBear2w ago
My guess would be to put Reverse first. Linq also has a lot of shortcuts for common collection types and I wouldn't be surprised if Reverse didn't simply enumerate with a decreasing index for arrays. It's always possible to look into the underlying code of .NET to confirm for yourself, in this case by looking at the body of Reverse
Angius
Angius2w ago
If you don't want to reverse:
var result = nubers
.Where(n => n > 100)
.Skip(numbers.Length - 3);
var result = nubers
.Where(n => n > 100)
.Skip(numbers.Length - 3);
Joschi
Joschi2w ago
Reverse() indeed completely enumerates the IEnumerable<T> and copies the result into a new T[]. It then returns the elements of the newly created array in reverse order.
Jason_Bjorn
Jason_Bjorn2w ago
Yeah, we talked about it in #advanced @Joschi
Joschi
Joschi2w ago
Did they by any chance elaborate on why? Because for IList<T> implementations shouldn't it be possible to just yield the content in reverse order using the index?