4

If I have an Effect collection that's IEnumerable<Effect>, how do I set their .Name property based on their location in the collection?

So in the end, I just want them to be renamed starting from 1 to n.

<inside the collection>
effectInstance1.Name = Effect 1;
effectInstance2.Name = Effect 2;
effectInstance3.Name = Effect 3;
...

Is this possible with Linq?

Joan Venge
  • 315,713
  • 212
  • 479
  • 689

3 Answers3

8

LINQ isn't really intended for mutation anyway; however, you could use something like the Select overload that includes the index. But to be honest? Just loop and keep a counter. Much easier to understand, and that matters.

int position = 0;
foreach(var obj in collection) {
    position++;
    obj.Name = "Effect " + position.ToString();
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • You really want to use string concatenation in a loop? You probably know better than I do; when do you "break even" using String.Format and StringBuilder over simple concatenation? – KeithS Feb 03 '11 at 23:47
  • @KeithS: what would you do with a StringBuilder? – Jimmy Feb 03 '11 at 23:51
  • @KeithS using StringBuilder is meaningful if you do concat of single `string` variable like `string s = ""; foreach (...) s += x;`. here just two strings are concated on every iteration. `StringBuiler`'s overhead will be bigger. – Andrey Feb 03 '11 at 23:51
  • The question was about solving with LINQ, why we shoud propose other solutions? – Restuta Feb 04 '11 at 00:07
  • @KeithS : I have to echo everything Andrey said; StringBuilder *per iteration* would be silly here, compared to a single call to `Concat` per item. – Marc Gravell Feb 04 '11 at 00:11
  • @Restuta - consider the question: "how do I put a screw in with a hammer?" now... is the correct answer "hit them harder", or is it "use nails, or use a screwdriver" ? – Marc Gravell Feb 04 '11 at 00:12
  • I belive it is "hit them harder like this, *but* it is better to use screwdriver". – Restuta Feb 04 '11 at 00:16
  • @Marc, Audrey - I wasn't implying that StringBuilder should be used in this particular case. I probably should have left it at String.Format, which my own answer utilizes. So, to restate; why did you use string concatenation when best practices generally discourage that in favor of String.Format()? – KeithS Feb 04 '11 at 00:26
  • @KeithS I strongly disagree that string.Format would be a best practice here *at all*. Given the problem statement, vanilla concatenation is a valid and sensible option. – Marc Gravell Feb 04 '11 at 00:29
  • @KeithS: at this level, the only question should be about readability. string.Format is actually slower than concatenation in this example anyways, since it uses an internal stringbuilder. Anyhoo, there's an entire question devoted to this topic at http://stackoverflow.com/questions/296978/when-is-it-better-to-use-string-format-vs-string-concatenation – Jimmy Feb 04 '11 at 00:30
  • @Jimmy @KeithS actually I'd argue more from the ange of "what is it doing to help us?" - in both cases, as presented, to change the text we have to edit the code. So until we need a resource-based i18n engine, and considerig that were just concatenating two basic values, let's stick with "simple"... IMO. As a minor note is also avoids some string parsing, some boxing, and a virt-call vs static-call, but those are all very cheap. – Marc Gravell Feb 04 '11 at 00:33
1
var n = 0;
collection.ForEach(x=>x.Name = "Effect {0}".FormatWith(++n));

These are simple extension methods I bodged up back in 3.5:

public static void ForEach<T>(this IEnumerable<T> collection, Action<T> lambda)
{
    foreach(var element in collection)
        lambda(element);
}

public static string FormatWith(this string base, params object[] args)
{
    return String.Format(base, args);
}
KeithS
  • 70,210
  • 21
  • 112
  • 164
  • I kind of wish this was the default method of formatting strings (a la Python's `string.format`) but I can't see the value of hiding a foreach statement inside a (side-effecting!) ForEach extension method. but it smells very Ruby-like, so I guess there must be people who like that style. – Jimmy Feb 04 '11 at 00:44
  • It is indeed a stylistic preference, and I never said it was side-effect free. I find it to be easier to stick this on the end of a Linq chain or collection when the repetitive action is simple. Best case, it's a method I can express as a delegate reference: `collection.ForEach(collection2.Add);` – KeithS Feb 04 '11 at 00:55
1

It is not the best thing to solve with LINQ, but is possible:

class Program
{
    private class Effect
    {
        public string Name { get; set; }
    }

    static void Main(string[] args)
    {
        List<Effect> list = new List<Effect> {new Effect(), new Effect(), new Effect()};

        var newElements = list.Select((element, index) =>
        {
            element.Name = "Effect " + index.ToString();
            return element;
        });


        foreach (var effect in newElements)
        {
            Console.WriteLine(effect.Name);
        }
    }
}

Outputs:

Effect 0

Effect 1

Effect 2

Restuta
  • 5,855
  • 33
  • 44