user437329
user437329

Reputation:

Generate missing list values in c# list using Linq

I have a list that contains the following class

    public class File
{
    public string Name{get;set;}
    public int Year{get;set;}
    public decimal Amount{get;set;}

}

My list could contain i.e List

Name="File 1" Year=2011 Amount=200
Name="File 2" Year=2012 Amount=400
Name="File 3" Year 2013 Amount=500

I would like the above list to be transform to contain the following values

Name="File 1" Year=2011 Amount=200
Name="File 1" Year=2012 Amount=0
Name="File 1" Year 2013 Amount=0
Name="File 2" Year=2011 Amount=400
Name="File 2" Year=2012 Amount=0
Name="File 2" Year 2013 Amount=0
Name="File 3" Year 2011 Amount=0
Name="File 3" Year=2012 Amount=0
Name="File 3" Year 2013 Amount=500

Note that the other items with an amount of 0 are automatically generated for the missing years

Upvotes: 1

Views: 179

Answers (2)

Marc Gravell
Marc Gravell

Reputation: 1064234

foreach(var name in files.Select(x => x.Name).Distinct())
foreach(var year in files.Select(x => x.Year).Distinct())
{
    var amount = (from file in files
                  where file.Name == name
                     && file.Year == year
                  select (decimal?)file.Amount).SingleOrDefault() ?? 0M;
    Console.WriteLine("Name={0}, Year={1}, Amount={2}",
                  name, year, amount);
}

Obviously it could be optimized - especially as a lookup for the amount via a dictionary; maybe:

var amounts = files.ToDictionary(
        file => new {file.Name,file.Year}, file => file.Amount);

foreach(var name in files.Select(file => file.Name).Distinct())
foreach(var year in files.Select(file => file.Year).Distinct())
{
    decimal amount;
    if(!amounts.TryGetValue(new {file.Name,file.Year}, out amount) amount = 0M;
    Console.WriteLine("Name={0}, Year={1}, Amount={2}",
                  name, year, amount);
}

Upvotes: 3

Joffrey Kern
Joffrey Kern

Reputation: 6499

For the default value, you can add a constructor :

public class File
{
    public File() { this.Amout = 0; }

    public string Name{get;set;}
    public int Year{get;set;}
    public decimal Amount{get;set;}
}

For the OrderBy, you can look on this example

Upvotes: 0

Related Questions