# "Select followed by First" versus "First followed by Select" when summing the data for a student

I am wondering which one I should choose between the following two options when I need to calculate the sum of Data of the student with Id of 1.

var out1 = students
.Select(x => new { Id = x.Id, Sum = x.Data.SelectMany(n => n).Sum() })
.FirstOrDefault(s => s.Id == 1)
.Sum;

var out2 = students
.FirstOrDefault(s => s.Id == 1)
.Data.SelectMany(n => n)
.Sum();


class Student
{
public int Id { get; set; }
public List<List<int>> Data { get; set; }
}

class Program
{
static void Main()
{
var a = new Student
{
Id = 1,
Data = new List<List<int>>
{
new List<int>{ 1,2,3},
new List<int>{ 4,5,6}
}
};

var b = new Student
{
Id = 2,
Data = new List<List<int>>
{
new List<int>{ 7,8,9},
new List<int>{ 10,11,12}
}
};

var c = new Student
{
Id = 3,
Data = new List<List<int>>
{
new List<int>{ 13,14,15},
new List<int>{ 16,17,18}
}
};

var students = new List<Student> { a, b, c };

var out1 = students
.Select(x => new { Id = x.Id, Sum = x.Data.SelectMany(n => n).Sum() })
.FirstOrDefault(s => s.Id == 1)
.Sum;

var out2 = students
.FirstOrDefault(s => s.Id == 1)
.Data.SelectMany(n => n)
.Sum();

Console.WriteLine(out1);
Console.WriteLine(out2);

}
}

• Option 1 will mean you calculate the sum for potentially all elements just to throw them away. You definitely shouldn't do that option. Find the student first and then sum the data.
– RobH
Commented Jun 16, 2022 at 19:11

### Option 1

students
.Select(x => new { Id = x.Id, Sum = x.Data.SelectMany(n => n).Sum() })
.FirstOrDefault(s => s.Id == 1)
.Sum;

• .Select: Transforms all Student object in the collection into anonymous objects
• .FirstOrDefault: Finds the first anonymous object where the Id is matching with the predefined value
• .Sum: Accesses the Sum property of the anonymous object
• This is error-prone since FirstOrDefault might return with null if there is no matching element in the collection
• The fix could be ?.Sum

So, you might need to iterate through twice of the collection (once to transform all elements then if the Id == 1 matches with the last element). So, the order of this function is O(2n).

### Option 2

students
.FirstOrDefault(s => s.Id == 1)
.Data.SelectMany(n => n)
.Sum();

• FirstOrDefault: Finds the first Student object where the Id is matching with the predefined value
• .Data.SelectMany: Flattens the nested collection of collections to a collection
• It is error-prone since FirstOrDefault might return with null
• .Sum(): Aggregates the items in the flatten collection

The order of this function is O(n), since Id == 1 might find the last element.

### Alternatives

• If you would store your Students in a Dictionary then the lookup would be O(1)
Dictionary<int, List<List<int>>> students = ...
var result = students[1].SelectMany(n => n)?.Sum();

• You could use two Sum calls instead of SelectMany + Sum
var result = students[1].Sum(n => n.Sum());


Please be aware that the indexer operator could throw KeyNotFoundException rather than return with null

• "So, the order of this function is O(2n)." That's not how LINQ works. Commented Jun 16, 2022 at 11:45
• @Johnbot Yes, you are correct. Due to the lazy evaluation it will build an expression tree and it might optimise on this when it iterates through the collection. Commented Jun 16, 2022 at 12:15
• @Johnbot It's also possible to check the source-code in github or referencesource.microsoft.com, to know how does LINQ work. (which would give you a good idea on which approach would be feasible to the code).
– iSR5
Commented Jun 16, 2022 at 14:54
• @Johnbot is correct - the source collection will only be iterated once it is not 2n.
– RobH
Commented Jun 16, 2022 at 19:12