简体   繁体   中英

Linq: set a property while doing a projection

I'm doing a simple GroupBy taking the First element but I want to modify one of the property of each result.

class M
{
 public string Name {get; set;}
 public int NOfPeopleWithTheSameName {get; set;}
 public string P1 {get; set;}
 public string P2 {get; set;}
 public string P3 {get; set;}
 public string P4 {get; set;}
 public string P5 {get; set;}
}  


List<M> myList = GetMyList();


var l2 = myList
   .GroupBy(m => m.Name)
   .Select(group => new M { Name = group.Key, NOfPeopleWithTheSameName = group.Count() });

This is pretty easy, but this way is not the best if the class has many properties (since every property value should be copied to the new one)? I should copy them one by one.

I would like to simply take the element and change the property NOfPeopleWithTheSameName

You don't need to create a new M , you can return the existing one, for example:

var l2 = myList
   .GroupBy(m => m.Name)
   .Select(group => 
   {
        var m = group.First();
        m.NOfPeopleWithTheSameName = group.Count();
        return m;
   });

However, if you are going to add a property to your model just for this, I would suggest instead having a different class that wraps the initial model and the count - don't pollute your models. For example, you could have a generic wrapper class like this:

public class ModelCount<T>
{
    public T Model { get; set; }
    public int Count { get; set; }
}

And now group like this:

var l2 = myList
   .GroupBy(m => m.Name)
   .Select(group => new ModelCount<M> 
   {
        Model = group.First(),
        Count = group.Count()
   });

Yes, you can ...

class Test 
{
    public string Name { get; set; }
    public int Number { get; set; }
}

var tests = new List<Test> { /* ... your data here ... */ };

var modifiedTests = tests.Select(test => { test.Name = "MODIFIED"; return test; });

// this actually executes above query and modifies your original items in the list:
var modifiedMaterialized = modifiedTests.ToList();

But you really, really(!) should not!

LinQ is language integrated query . Having a query with side effects is evil. Mustache twisting evil. Just don't, you will save yourself a lot of pain.


I think what you want is just not LinQ, but regular loops:

class M
{
 public string Name {get; set;}
 public int NOfPeopleWithTheSameName {get; set;}
 public string P1 {get; set;}
 public string P2 {get; set;}
 public string P3 {get; set;}
 public string P4 {get; set;}
 public string P5 {get; set;}
}  

List<M> myList = GetMyList();

var groups = myList.GroupBy(m => m.Name).ToList();

foreach(var group in groups)
{
    foreach(var member in group)
    {
        member.NOfPeopleWithTheSameName = group.Count();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM