tags:

views:

152

answers:

4

How can I replace ConvertListToString(extensions) with an elegant LINQ statement?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestExtn2343
{
    class Program
    {
        public static void Main(string[] args)
        {
            string[] files = { "test.txt", "test2.txt", 
                               "test.as", "notes.doc", 
                               "data.xml", "test.xml", 
                               "test.html", "notes.txt", 
                               "test.xls" };

            List<string> extensions = (from file in files
                             let index = file.LastIndexOf('.') + 1
                             select file.Substring(index)).Distinct().ToList<string>();

            Console.WriteLine("The kinds of file extensions used are {0}.", ConvertListToString(extensions));
            Console.ReadLine();
        }

        public static string ConvertListToString(List<string> list) {
            StringBuilder sb = new StringBuilder();
            int count = 1;
            foreach (var listItem in list)
            {
                sb.Append(listItem.ToUpper());
                if (count != list.Count)
                    sb.Append(", ");
                count++;
            }
            return sb.ToString();
        }

    }
}
+15  A: 

Here's how:

String s = String.Join(", ", (from extension in extensions select extension.ToUpper()).ToArray());

Note, I would probably not write this as one line, rather like this:

String s = String.Join(", ",
    (from extension in extensions
     select extension.ToUpper()).ToArray());

If you don't mind just going for the Linq extension methods directly, instead of the Linq query syntax, you can use this:

String s = String.Join(", ", extensions.Select(e => e.ToUpper()).ToArray());

Another variant would be to just call ToUpper on the final string instead:

String s = String.Join(", ", extensions.ToArray()).ToUpper();

And finally, in .NET 4.0, String.Join finally supports IEnumerable<String> directly, so this is possible:

String s = String.Join(", ", extensions).ToUpper();

Note that per your question, this might lead to duplicates nonetheless. Consider what would happen if your original list of filenames contained both "filename.txt" and "filename.TXT", these would be counted as two distinct extensions.

The call to ToUpper should be moved up before the call to Distinct to fix this.

Instead of the original Linq expression + code, I would rewrite the whole thing to this:

String[] distinctExtensions = files
    .Select(fileName => Path.GetExtension(fileName).ToUpper())
    .Distinct()
    .ToArray();
String distinctExtensionsAsString = String.Join(", ", distinctExtensions);

If you add the following utility method to your code library, you can simplify it further:

public static class StringExtensions
{
    public static String Join(this IEnumerable<String> elements, String separator)
    {
        if (elements is String[])
            return String.Join(separator, (String[])elements);
        else
            return String.Join(separator, elements.ToArray());
    }
}

and then your code can look like this:

String distinctExtensionsAsString = files
    .Select(fileName => Path.GetExtension(fileName).ToUpper())
    .Distinct()
    .Join(", ");
Lasse V. Karlsen
+17  A: 
var s = string.Join(", ", files.Select(file => Path.GetExtension(file))
    .Distinct(StringComparer.InvariantCultureIgnoreCase).ToArray());
Marc Gravell
This is a better answer than mine, as this replaces more of his original code with Linq, rather than just answering his exact question. My vote goes here.
Lasse V. Karlsen
Wrong! It's 2 lines.
Henk Holterman
Note that this is also a very good example of why it is not a good idea to accept answers as quick as possible. Instead, even though you decide upon which answer you yourself want to use early on, leave the question open for a while longer to see if better answers bubble to the top.
Lasse V. Karlsen
This is slightly incorrect; the extensions are meant to be uppercased. Note also that `file => Path.GetExtension(file)` is nicer as `Path.GetExtension`.
Porges
@Porges - try it ;-p If you use Path.GetExtension, you need to specify the generics explicitly.
Marc Gravell
A: 

How about this:

String output = String.Join(", ",(from file in files
  let index = file.LastIndexOf('.') + 1
  select file.Substring(index)).Distinct().ToArray<string>());
Lazarus
+1  A: 

How about this...

public static string ConvertListToString(List<string> list) 
{ 
    return list.Aggregate((x, y) => x + ", " + y).ToUpper();
}

This does it in one line, and I've moved the "ToUpper" out onto the final string so it's only called once.

Clearly you could then throw away the method ConvertListToString and inline if you wanted.

Martin Peck