tags:

views:

273

answers:

4

I have a list like:

List<String> test = new List<String> {"Luke", "Leia"};

I would like to use something like this:

test.Select(s => String.Format("Hello {0}", s));

but it doesn't adjust the names in the list. Is there a way to use lambda expressions to alter these? Or is it because strings are immutable that this doesn't work?

+8  A: 

Select doesn't modify the original collection; it creates a new IEnumerable<T> that you can enumerate with a foreach or convert to a list:

List<String> test2 = test.Select(s => String.Format("Hello {0}", s)).ToList();

test still contains "Luke" and "Leia", and test2 contains "Hello Luke" and "Hello Leia".


If you want to modify the original list with a lambda expression, you can apply the lambda expression to each list item individually and store the result back in the collection:

Func<string, string> f = s => String.Format("Hello {0}", s);

for (int i = 0; i < test.Count; i++)
{
    test[i] = f(test[i]);
}
dtb
Thanks, the first one succeeded for me.
Nyla Pareska
@Nyla Pareska: That version does not modify the original collection which seemed to be your intent ("but it doesn't adjust the names in the list"). If you want to do that, please see the extension method that I provided in my answer.
Jason
A: 

You could just do a foreach statement:

test.ForEach(s=>String.Format("Hello {0}", s));

That is if you are trying to just update the names.

Joshua Cauble
ForEach takes an `Action<T>` and does not modify the `List<T>`
dtb
String.Format returns a new string, but does not modify the original string.
M4N
Ok, so update it as such: s=> s = String.Format("Hello {0}", s)); It all depends on what he was wanting to do anyway, return a new list with updated values or update the original list.
Joshua Cauble
`ForEach(s=> s = String.Format("Hello {0}", s)))` doesn't do anything as well.
dtb
dtb-> Sorry, my bad, I'm so used to using Reference types that I can modify that I forgot value types work differently in this scenario. In this case you would have to use the for(;;) syntax to accomplish the same thing.
Joshua Cauble
`String` is a reference type. You're confusing call-by-sharing with call-by-reference.
dtb
+3  A: 

Here:

for(int i = 0; i < test.Count; i++) {
    test[i] = String.Format("Hello {0}", test[i]);
}

No need to be fancy. No need to abuse LINQ. Just keep it simple.

You could go one step beyond this and create an extension method like so:

static class ListExtensions {
    public static void AlterList<T>(this List<T> list, Func<T, T> selector) {
        for(int index = 0; index < list.Count; index++) {
            list[index] = selector(list[index]);
        }
    }
}

Usage:

test.AlterList(s => String.Format("Hello {0}", s));

Select is for projecting and is really intended to be used in circumstances where there are no side-effects. Manipulating the items in the list very clearly has side-effects. In fact, the line

test.Select(s => String.Format("Hello {0}", s));

doesn't do anything except creating an IEnumerable<string> that could eventually be enumerated over to produce the projection.

Jason
I don't understand how he would be abusing LINQ. He would be using it exactly as it was intended to be used. His question also specifically asked how to perform the task using a lambda expression.
Justin R.
`Select` is not meant to be used for causing side effects.
Jason
@Downvoter: Please leave a comment as to why you downvoted.
Jason
I did. My apologies for not mentioning it in my original comment. When I read over the original question, I must have skimmed over the part where he said he was trying to *alter* the list of strings. In that circumstance, I will agree that LINQ is not an appropriate tool to use.
Justin R.
@Justin Rusbatch: (Responding to the edit of your comment.) Yes, he asked about lambda expression. He also asked specifically about using `Select`. Trying to fenagle `Select` to modify the list would be an abuse of LINQ. As for using lambda expressions, I have provided an extension method that does the job.
Jason
@Justin Rusbatch: So what is it about my answer that led you to downvote? I believe that I answered the question, provided background on why `Select` shouldn't be use to do this, and provided a solution (an extension method) that works. I do not see any inaccuracies in my post but would like to know if there are any.
Jason
Yep, we're in agreement now -- I will undo my downvote. I read your answer with the assumption that he would enumerate over the list projected by `Select`, but looking back over his question I see that he was indeed trying to modify the list he had.
Justin R.
Thanks for coming back and responding to my comments. Much appreciated.
Jason
A: 

One other possible solution:

List<String> test = new List<String> {"Luke", "Leia"};
List<string> FormattedStrings = new List<string>();
test.ForEach(testVal => FormattedStrings.Add(String.Format("Hello {0}", testVal)));