5

It's been a while since I've used lambda expressions or LINQ and am wondering how I would do the following (I know I can use a foreach loop, this is just out of curiosity) using both methods.

I have an array of string paths (does it make a difference if it's an array or list here?) from which I want to return a new list of just the filenames.

i.e. using a foreach loop it would be:

string[] paths = getPaths();
List<string> listToReturn = new List<string>();
foreach (string path in paths)
{
    listToReturn.add(Path.GetFileName(path));
}

return listToReturn;

How would I do the same thing with both lambda and LINQ?

EDIT: In my case, I'm using the returned list as an ItemsSource for a ListBox (WPF) so I'm assuming it's going to need to be a list as opposed to an IEnumerable?

2
  • maybe there are similar questions already in SO? Commented Mar 24, 2011 at 12:10
  • Re the Edit: Yes, use a .ToList() in the last stage. Commented Mar 24, 2011 at 22:56

5 Answers 5

18

Your main tool would be the .Select() method.

string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p));

does it make a difference if it's an array or list here?

No, an array also implements IEnumerable<T>


Note that this minimal approach involves deferred execution, meaning that fileNames is an IEnumerable<string> and only starts iterating over the source array when you get elements from it.

If you want a List (to be safe), use

string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p)).ToList();

But when there are many files you might want to go the opposite direction (get the results interleaved, faster) by also using a deferred execution source:

var filePaths = Directory.EnumerateFiles(...);  // requires Fx4
var fileNames = filePaths.Select(p => Path.GetFileName(p));

It depends on what you want to do next with fileNames.

Sign up to request clarification or add additional context in comments.

6 Comments

+1 for not explicitly iterating over the result and turning it into a List<string>.
@Henk: no, the other upvoted post finishes with a ToList() call. I like the fact that your sample doesn't do that.
@Fredrik: I think when the question explicitly requests a list, answers should probably either create a list or say why they're not doing so.
You really can replace p => Path.GetFileName(p) with Path.GetFileName.
@Jon: you have a good point there (which I agree on; a brief explanation would be in its place), but I often see people use List<T> simply because they are unaware of the alternatives, so I tend to like answers that "stop in time". I am not saying that the OP is unaware of this, but there is nothing in the post indicating that there is actual need for anything that is not offered by IEnumerable<T> (apart from the variable declaration).
|
6

I think by "LINQ" you really mean "a query expression" but:

// Query expression
var listToReturn = (from path in paths
                    select Path.GetFileName(path)).ToList();

// Extension methods and a lambda
var listToReturn = paths.Select(path => Path.GetFileName(path))
                        .ToList();

// Extension methods and a method group conversion
var listToReturn = paths.Select(Path.GetFileName)
                        .ToList();

Note how the last one works by constructing the projection delegate from a method group, like this:

Func<string, string> projection = Path.GetFileName;
var listToReturn = paths.Select(projection).ToList();

(Just in case that wasn't clear.)

Note that if you don't need to use this as a list - if you just want to iterate over it, in other words - you can drop the ToList() call from each of these approaches.

Comments

5

It's just:

var listToReturn = getPaths().Select(x => Path.GetFileName(x)).ToList();

As already stated in other answers, if you don't actually need a List<string> you can omit the ToList() and simply return IEnumerable<string> (for example if you just need to iterate it, IEnumerable<> is better because avoids the creation of an other list of strings)

Also, given that Select() method takes a delegate, and there's an implicit conversion between method groups and delegates having the same signature, you can skip the lambda and just do:

getPaths().Select(Path.GetFileName)

2 Comments

There's no point in lambda when you can just pass the function. Also, I think it makes sense to state that IEnumerable returned by Select is sufficient for enumeration and list conversion may not be required.
@gaeron: yes, there's no need in using lambda. Anyway, I think that's negligibly faster then lambda and the latter is more readable IMO. BTW, edited :)
4

You could do it like this:

return getPaths().Select(Path.GetFileName);

Comments

1
listToReturn = paths.ToList().Select(p => Path.GetFileName(p));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.