2

I have a list of object. The object looks like so

public class GenericRecord
{
    public string GroupName { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Col1 { get; set; }
    public string Col2 { get; set; }
    public string Col3 { get; set; }
    public float ConvertedCol1 { get; set; }
    public float ConvertedCol3 { get; set; }
    public float ConvertedCol3 { get; set; }
}

I want to use fluent LINQ to parse the the Col1,Col2, and Col3 properties and then sum them.

I would like to do something like this

IEnumerable<GenericRecord> records = ...;
var summaries = records.Select(x => new GenericRecord 
{
   float.TryParse(x.Col1, out ConvertedCol1),
   float.TryParse(x.Col2, out ConvertedCol2),
   float.TryParse(x.Col3, out ConvertedCol3),
   GroupName => x.GroupName
}).GroupBy(x => x.GroupName)
.Select(x => new {
   GroupName = x.Key,
   Total1 = x.Sum(y => y.ConvertedCol1),
   Total2 = x.Sum(y => y.ConvertedCol2),
   Total3 = x.Sum(y => y.ConvertedCol3),
   Count = x.Count()
}).ToList();

However, that float.TryParse syntaxt in linq does not work.

How can I parse multiple columns using Fluent LINQ?

Jaylen
  • 39,043
  • 40
  • 128
  • 221

3 Answers3

3

Put processing in a method:

private static GenericRecord ConvertGenericRecord(GenericRecord x) {
    float c1, c2, c3;
    float.TryParse(x.Col1, out c1);
    float.TryParse(x.Col2, out c2);
    float.TryParse(x.Col3, out c3);
    return new GenericRecord {
        ConvertedCol1 = c1;
        ConvertedCol2 = c2;
        ConvertedCol3 = c3;
        GroupName = x.GroupName
    };
}

Use the method as follows:

var summaries = records
    .Select(ConvertGenericRecord)
    .GroupBy(x => x.GroupName)
    .Select(x => new {
        GroupName = x.Key,
        Total1 = x.Sum(y => y.ConvertedCol1),
        Total2 = x.Sum(y => y.ConvertedCol2),
        Total3 = x.Sum(y => y.ConvertedCol3),
        Count = x.Count()
    }).ToList();

Calls to TryParse wouldn't work in EF or LINQ2SQL. If you are reading from DB, add AsEnumerable() or ToList() before invoking ConvertGenericRecord.

If the conversion must take place on the DB side, replace TryParse with SqlFunctions.StringConvert(...) (detailed Q&A).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

You cant use an object initializer syntax that way. It needs the name of the property on the left hand side, not with a reference.

Perhaps GenericRecord can have a constructor and do the conversion for you or have the properties convert it for you.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
  • The `records` object is populated from a database. The only other way I can convert it is by adding a function to that object which will handle the tryparse for me. However, I won't be able to use my custom function in LINQ to sum the parsed data, Is there another way to do this beside using constructors? – Jaylen Jan 22 '18 at 21:03
0

Operations are not supported within an object initilizer, if you look at a object initiliser for your Generic Record class:

var record = new GenericRecord
{
    GroupName = "Group",
    CreatedAt = DateTime.Now,
    Col1 = "Col1",
    Col2 = "Col2",
    Col3 = "Col3",
};

It may be obvious as to what you issue may be, if I were you I would push this functionality into the constructor of Generic Record:

public GenericRecord(string col1, string col2, string col3, string groupName)
{
   float convertedVal1;
   if (float.TryParse(col1, out convertedVal1))
   {
      ConvertedCol1 = convertedVal1;
   }
}

now your Linq statement will be much easier:

var summaries = records.Select(x => new GenericRecord(x.Col1, x.Col2, x.Col3, x.GroupName))
            .GroupBy(x => x.GroupName)
            .Select(x => new {
                GroupName = x.Key,
                Total1 = x.Sum(y => y.ConvertedCol1),
                Total2 = x.Sum(y => y.ConvertedCol2),
                Total3 = x.Sum(y => y.ConvertedCol3),
                Count = x.Count()
            }).ToList();

Edit: Another possible solution to this, if you don't mind the non-safe casting is to use float.Parse:

https://msdn.microsoft.com/en-us/library/2thct5cb(v=vs.110).aspx

var summaries = records.Select(x => new GenericRecord
            {
                ConvertedCol1 = float.Parse(x.Col1),
                ConvertedCol2 = float.Parse(x.Col2),
                ConvertedCol3 = float.Parse(x.Col3),
                GroupName = x.GroupName
            })
            .GroupBy(x => x.GroupName)
            .Select(x => new {
                GroupName = x.Key,
                Total1 = x.Sum(y => y.ConvertedCol1),
                Total2 = x.Sum(y => y.ConvertedCol2),
                Total3 = x.Sum(y => y.ConvertedCol3),
                Count = x.Count()
            }).ToList();

Hope this helps

Mark Davies
  • 1,447
  • 1
  • 15
  • 30