goscamp
goscamp

Reputation: 1106

Select Distinct rows when only one columns is different Linq

I have a data = List<Model>, where Model looks like this

public class Model{
    public string String1 { get; set; }
    public int Int1{ get; set; }
    public int Int2{ get; set; }
    public string String2 { get; set; }
    public decimal Decimal1{ get; set; }
    ...
    public decimal DecimalN{ get; set; }
}

I want to have average of each DecimalX values group by String1, Int1, Int2, but my problem is that sometimes I have two or more the same rows and only String2 is different, so I would like to do Distinct, but doesn't work because of this String2 property. I was trying to change all values of String2 to null or empty string

var x = data.ForEach(x => x.String2= null);

but I receive error Cannot asign void to implicitly- typed variable.

Upvotes: 0

Views: 143

Answers (4)

cap29
cap29

Reputation: 996

Just like Reniuz said that error occurs becaus forEach doesn't return anything (void).

Returning to your main problem, you mentioned that you need the average value for each Decimal.

For Decimal1 you can do something like this:

var b = list.GroupBy(g => new { g.String1, g.Int1, g.Int2 }).Select(r=> new {r.Key.String1, r.Key.Int1, r.Key.Int2, avgDecimal1 = r.Select(g=>g.Decimal1).Average()}).ToList();

First you need to Group by the elements that are going to be your keys (without String2 like you said) and after that, select those keys and the AVG of the elements of a determined property (e.g. Decimal1). You can add more AVG functions if you want (avgDecimal2, avgDecimal3, etc)

Upvotes: 1

Sria Pathre
Sria Pathre

Reputation: 182

I don't understand why you want distinct values. May be you can provide an example. One solution can be -

  var result = data.GroupBy(x => new { x.String1, x.Int1, x.Int2 })
                        .Select(g => new
                        {
                            String1 = g.Key.String1,
                            Int1 = g.Key.Int1,
                            Int2 = g.Key.Int2,
                            AvgDecimal1 = g.Select(x => x.Decimal1).Average(),
                            AvgDecimal2 = g.Select(x => x.Decimal1).Average(),
                            AvgDecimalN = g.Select(x => x.Decimal1).Average()
                        }).ToList();

If you want distinct values you can add distinct before group by -

 data.Select(d => new Model { String1 = d.String1, Int1 = d.Int1, Int2 = d.Int2, Decimal1 = d.Decimal1, Decimal2 = d.Decimal2, DecimalN = d.DecimalN }) //returning new collection with String2 as null
                    .Distinct()

First solution produces following result - enter image description here

Upvotes: 0

reckface
reckface

Reputation: 5878

you want to start with projecting your results with the values you want to work with or in the way you want to work with them.

var query = source.Select(e => new
{
    e.String1,
    e.Int1,
    e.Int2,
    e.Decimal1,
});

Just omit the properties you don't want.

// or go straight to your average
var sum = data.GroupBy(e => new
{
    e.String1,
    e.Int1,
    e.Int2,
    e.Decimal1,
}).Average(e => e.Key.Decimal1);

Upvotes: 0

Renatas M.
Renatas M.

Reputation: 11820

ForEach does not return anything - it's is void method, so your assignment to x is not valid. Instead of this:

var x = data.ForEach(x => x.String2= null);

You should do like this:

data.ForEach(x => x.String2= null);

Upvotes: 1

Related Questions