tags:

views:

131

answers:

4

This code:

string[] files = {"test.txt", 
    "test2.txt", 
    "notes.txt", 
    "notes.doc", 
    "data.xml", 
    "test.xml", 
    "test.html", 
    "notes.txt", 
    "test.as"};

files.ToList().ForEach(f => Console.WriteLine(
     f.Substring(
      f.IndexOf('.') + 1, 
      f.Length - f.IndexOf('.') - 1
      )
    ));

produces this list:

txt
txt
txt
doc
xml
xml
html
txt
as

Is there some way to make f.IndexOf('.') a variable so that in more complex LINQ queries I have this defined in one place?

+2  A: 

You could do this

files.ToList().ForEach(f => { var i = f.IndexOf('.'); 
   Console.WriteLine(f.Substring(i + 1, f.Length - i - 1));}
);

but IMO it is approaching the limits of what you should do in a lambda.

Brian Rasmussen
+10  A: 

If you were using Linq then you could use the let keyword to define an inline variable (the code posted in the question isn't actually using Linq).

var ext = from file in files
          let idx = f.LastIndexOf('.') + 1
          select file.Substring(idx);

However for the specific scenario you've posted I'd recommend using Path.GetExtension instead of parsing the string yourself (for example, your code will break if any of the files have a . in the file name).

var ext = from file in files select Path.GetExtension(file).TrimStart('.');
foreach (var e in ext)
{
    Console.WriteLine(e);
}
Greg Beech
+1 for the "let" keyword.
Dave Markle
+1 for teaching him fishing extensions
ssg
fishing extensions?
Svish
A: 

In LINQ it would look like this, (ignoring proper way of extracting filename extensions to mention "let"):

var q = from f in files
        let i = f.IndexOf('.')
        select f.Substring(i + 1, f.Length - i - 1);
foreach(f in q)
{
    Console.WriteLine(f);
}

Note that extensionless file names might create problems :)

ssg
A: 

If you don't want to use the from kind of syntax, you can do something similar with the Select method:

var extensions = files
        .Select(x => new { Name = x, Dot = x.IndexOf('.') + 1 })
        .Select(x => x.Name.Substring(x.Dot));

Although, like Greg, I would recommend using the Path.GetExtension method. And with methods, that could like like this:

var extensions = files
        .Select(x => Path.GetExtension(x));

And in this case I really think that is a lot easier to read than the suggested linq statements.


To write it to the console, you can do this:

extensions
    .ToList()
    .ForEach(Console.WriteLine);
Svish