Vahid
Vahid

Reputation: 5444

Change the property of objects in a List using LINQ

I have list of Beam objects. How can I change the IsJoist property of the beams when the Width property is greater than 40 using LINQ?

class Beam
{
    public double Width { get; set; }
    public bool IsJoist { get; set; }
}

var bm1 = new Beam { Width = 40 };
var bm2 = new Beam { Width = 50 };
var bm3 = new Beam { Width = 30 };
var bm4 = new Beam { Width = 60 };

var Beams = new List<Beam> { bm1, bm2, bm3, bm4 };

Here is what I have done but I'm only getting a List. I want the new list to be the same as the original one except that the IsJoist property for some beams will be set to true.

var result = Beams
    .Where(x => x.Width > 40)
    .Select(x => x.IsJoist = true)
    .ToList();

I was able to implement this as below. Is it ok since LINQ is meant for queries?

var result = Beams
    .Where(x => x.Width > 40)
    .Select(x =>
    {
        x.IsJoist = true;
        return x;
    })
    .ToList();

Upvotes: 23

Views: 39476

Answers (6)

oglester
oglester

Reputation: 6655

The best way that I've found is to new up a copy of the object, with the modifications in the select. It would be nice if there was a spread like in js.

Some untested code that should convey the idea:


public class Cat {
   public string Name;
   public bool IsFerrel;
}

List<Cat> cats = new{
   new{Name="Tame"},
   new{Name="Wild"}
};

return cats.Select(c => new Cat{
  Name = c.Name,
  IsFerrel = c.Name.Contains("Wild")
};



Essentially, this takes a functional approach of not mutating the object.

Upvotes: 1

abdou93
abdou93

Reputation: 175

You can try this to change a property of all items in the list ( without any condition ).

Beams.All(b => b.IsJoist = true);

Upvotes: -1

Eric J.
Eric J.

Reputation: 150108

If your solution must be completely Linq, you could do

Beams.Where(x => x.Width > 40).ToList().ForEach(b => b.IsJoist = true);

However, that is not an ideal way to implement this (@Jacob's answer is a better one). Check out Eric Lippert's blog entry on the topic. The most important lines for me are

The first reason is that doing so violates the functional programming principles that all the other sequence operators are based upon. Clearly the sole purpose of a call to this method is to cause side effects. The purpose of an expression is to compute a value, not to cause a side effect. The purpose of a statement is to cause a side effect.

https://ericlippert.com/2009/05/18/foreach-vs-foreach/

Note that ToList() is called because List<T> provides a ForEach() method, while Linq in general does not offer such an extension method for the reasons Eric Lippert cites in that blog entry.

UPDATE

Your code both updates entities in the original list (changes IsJoist to true for certain conditions) and returns references to the objects that were updated. If that is what you intended, the code functions. However, Linq is designed with a functional paradigm in mind. Introducing side effects within the context of a Linq expression violates the functional programming principal behind the extension methods.

Upvotes: 44

Bhupinder Singh
Bhupinder Singh

Reputation: 49

Suppose I want to change value of Property Selected to true for particular object then I can do like this

Beams.Where(x => x.Width > 40).FirstorDefault(z=>z.Selected = true)

Upvotes: 2

Austin Harris
Austin Harris

Reputation: 1726

To be functionally pure, your linq would not alter the data that it is working on. This means that you would have to .Select(x=> new Beam(x) {IsJoist=true}). Then you would replace your original list with the results.

Upvotes: 1

Jacob Seleznev
Jacob Seleznev

Reputation: 8131

foreach(Beam beam in Beams.Where(x => x.Width > 40))
{
     beam.IsJoist = true;
} 

Upvotes: 13

Related Questions