1

I'm new to LinQ and started working with it a couple weeks ago. So maybe i have the wrong understanding how LinQ works. i also tried to use an empty constructor as stated here: Invoke constructor inside a linq query

I changed the constructor of a class. I added the entity energyType

public CSVMeter(int meterID, DateTime datum, int numberOfValues, double total, double total2, double qualityScore, int energyType)
    {
        this.MeterID = meterID;
        this.Datum = datum;
        this.NumberOfValues = numberOfValues;
        this.total = total;
        this.total2 = total2;
        this.qualityScore = qualityScore;
        this.energyType = energyType;
    }

I have the following LinQ query.

 public List<CSVMeter> getDisctinctMeters(List<CSVMeter> meterList)
    {
                    newMeterList = newMeterList.GroupBy(x => new { x.MeterID, x.Datum })
            .Select(x => new CSVMeter(
                x.Key.MeterID, 
                x.Key.Datum, 
                x.Sum(s => s.NumberOfValues), 
                x.Sum(s => s.total), 
                x.Sum(s => s.total2), 
                0, 
                x.energyType))
                .ToList();

        return meterList;

    }

but i get the following error at x.energyType

Error 2 'System.Linq.IGrouping' does not contain a definition for 'energyType' and no extension method 'energyType' accepting a first argument of type 'System.Linq.IGrouping' could be found (are you missing a using directive or an assembly reference?) c:\users\rudi\documents\visual studio 2013\projects\plooscassandra\plooscassandra\handlers\meterbuilder.cs 108 136 PloosCassandra

Why can't i find x.energyType ?

Community
  • 1
  • 1
Proliges
  • 371
  • 4
  • 26
  • 2
    Because that last `x` is not a single `CsvMeter` but an `IGrouping` with your anonymous type (`{MeterID, Datum}`) as `Key` and representing a sequence of `CsvMeter`. The `energyType` would be a property of the `s` you use in the `Sum` calls. – René Vogt Aug 10 '16 at 08:19
  • what is the definition for this object `newMeterList` – Anonymous Duck Aug 10 '16 at 08:20
  • You are grouping your data so energyType doesn't exists as a scalar field but as a list (like NumberOfValues and totals). – ema Aug 10 '16 at 08:22
  • @RenéVogt @ema But `energyType` is not something i want to add up. Its a fixed value i get. I can't use `x.Avarage` because that returns a double value and it is an int. – Proliges Aug 10 '16 at 08:30
  • @Proliges see my answer. And how "fixed" is this value? If it's the same for all, you can use my `First()` approach. If it's totally constant, maybe an instance property in `CsvMeter` is a wrong place to store it at all. – René Vogt Aug 10 '16 at 08:35
  • @RenéVogt did that, worked. Marked as correct. Btw its not totally constant. But the value is fixed once i retrieve it from a database. Its based on the `meterID`. But it can fluctuate when i use an other `meterID` – Proliges Aug 10 '16 at 08:48

2 Answers2

2

Since you do a grouping, the x in the Select's lambda is an IGrouping<CsvMeter> - not a single CsvMeter.

This IGrouping<CsvMeter> has a Key property of the anonymous type you created above and further represents a sequence of CsvMeter instances.

Since you already did sum Sum operations on that sequence, you actually should have known that. The question is, how you want to aggregate the energyType of all CsvMeter instances in the sequence to evaluate the energyType for your resulting new CsvMeter. Here is how to simply use the energyType of the first element in the group:

newMeterList.GroupBy(x => new { x.MeterID, x.Datum })
            .Select(x => new CSVMeter(
                x.Key.MeterID, 
                x.Key.Datum, 
                x.Sum(s => s.NumberOfValues), 
                x.Sum(s => s.total), 
                x.Sum(s => s.total2), 
                0, 
                x.First().energyType))
            .ToList();

First() returns the first CsvMeter instace in the group.


But maybe you actually wanted to group the CsvMeter instances by that energy type, too. So you could change the grouping to

newMeterList.GroupBy(x => new { x.MeterID, x.Datum, x.energyType })
      //...

and use that value in the Select:

.Select(x => new CSVMeter(
     x.Key.MeterID, 
     x.Key.Datum, 
     x.Sum(s => s.NumberOfValues), 
     x.Sum(s => s.total), 
     x.Sum(s => s.total2), 
     0, 
     x.Key.energyType))

BTW your code look a little weird: your getDisctinctMeters takes a parameter called meterList and that is returned without any change. Instead you use some newMeterList and did not show its declaration. For my answer I assumed your intention was this:

public List<CSVMeter> getDisctinctMeters(List<CSVMeter> meterList)
{
    var newMeterList = meterList.GroupBy // shortened for clarity
    return newMeterList;
}
René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • but it is also possible that the class used to create `newMeterList` instance does not have the property `energyType` since he is not using the `meterList` passed value – Anonymous Duck Aug 10 '16 at 08:28
  • 1
    @Sherlock Updated the answer to address this – René Vogt Aug 10 '16 at 08:33
  • @RenéVogt Okay i tried the `x.first()` option and it looks like this is the correct answer. Since the `energyType` is always the same. returning the first one is always correct. Also: about the code looking weird. Thats correct, i did not post the entire class since it would just be filling the page with useless information. I just used the pieces i had issues with. – Proliges Aug 10 '16 at 08:35
1

The return type of GroupBy is IGouping, representing the groups themselves, not IEnumerable<CSVMeter>, so x has no property energyType. That being said, you would have to clarify for which member of the group the energyType would have to be selected; energyType is not used in the grouping expression.

Codor
  • 17,447
  • 9
  • 29
  • 56
  • 1
    but it is also possible that the class used to create `newMeterList` instance does not have the property `energyType` since he is not using the `meterList` passed value – Anonymous Duck Aug 10 '16 at 08:28