8

I decided to try out LINQ for the first time to try and solve this question.

The results of my first foray into the wonderful world of LINQ looked like this:

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

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>() 
            { 
               "fred-064528-NEEDED1", 
               "xxxx", 
               "frederic-84728957-NEEDED2", 
               "sam-028-NEEDED3", 
               "-----", 
               "another-test" 
            };

            var result =
            from s in list
            where (from c in s where c == '-' select c).Count() == 2
            select s.Substring(s.LastIndexOf("-") + 1);

            foreach (string s in result)
                Console.WriteLine(s);
            Console.WriteLine("Press Enter");
            Console.ReadLine();
        }
    }
}

I'd like to know how I can improve the above solution to this contrived little example. I'm not too interested in whether I've used the best validation method, or how I could localise "Press Enter" or anything like that; I'm just interested in using this example to learn a little more about LINQ.

Community
  • 1
  • 1
Matt Jacobsen
  • 5,814
  • 4
  • 35
  • 49

5 Answers5

6
var result =
        from s in list
        where s.Count(x => x == '=') == 2
        select s.Substring(s.LastIndexOf("-") + 1);
nothrow
  • 15,882
  • 9
  • 57
  • 104
4

It can also be written using Lambda expressions:

var result =
            list.Where(s => (from c in s where c == '-' select c).Count() == 2).Select(
                s => s.Substring(s.LastIndexOf("-") + 1));

I prefer Lambda expressions over LINQ syntax because of the Fluent interface. IMHO it is more human readable.

heads5150
  • 7,263
  • 3
  • 26
  • 34
  • ahh: http://stackoverflow.com/questions/214500/which-linq-syntax-do-you-prefer-fluent-or-query-expression – Matt Jacobsen Aug 10 '10 at 11:20
  • Generally a fluent interface is implemented by using method chaining to relay the instruction context of a subsequent call. (A bit more involved than that but it'll do for now) In this case the method Where is called then the method Select is called. – heads5150 Aug 10 '10 at 11:23
4

This is pretty nice I think. Partly LINQ.

var result = String.Join("-", inputData.Split('-').Skip(2));

If there can't be any '-' after the first two then this will do (not LINQ):

var result = inputData.Split('-')[2];  //If the last part is NEE-DED then only NEE is returned. And will fail on wrong input
Lasse Espeholt
  • 17,622
  • 5
  • 63
  • 99
  • nice, but consumes more memory, than .Substring variant. – nothrow Aug 10 '10 at 11:28
  • 1
    I did var result = from s in list select String.Join("", s.Split('-').Skip(2)); Great idea, but it's snagging on the red herring entries (e.g. "xxxx") – Matt Jacobsen Aug 10 '10 at 11:30
  • @Yossarian Yes you are properly right about that. But it must be faster than Reg exp and I think it is pretty sleek syntacticly. If you want the fastest possible you should properly not use LINQ but a more imperative way. – Lasse Espeholt Aug 10 '10 at 11:31
4

I'm a big fan of Lambdas too...

    static void Main(string[] args)  
    {  
        Func<string, char, int> countNumberOfCharsInString = 
             (str, c) => str.Count(character => character == c);

        var list = new List<string>() 
        { "fred-064528-NEEDED1", 
           "xxxx", 
           "frederic-84728957-NEEDED2", 
           "sam-028-NEEDED3", 
           "-----", "another-test" 
        };

        list.Where(fullString => countNumberOfCharsInString(fullString,'-') == 2)
            .ToList()
            .ForEach(s => Console.WriteLine(s.Substring(s.LastIndexOf("-")+1)));

        Console.WriteLine("Press Enter");   
        Console.ReadLine();  
    } 
fletcher
  • 13,380
  • 9
  • 52
  • 69
4

I don't think this is an improvement, as it is less readable, but you can do it all in one-line using some of the inbuilt methods in the List class:

list.FindAll(s => s.ToCharArray().
    Where(c => c == '-').Count() ==2).
    ForEach(c => Console.WriteLine(c.Substring(c.LastIndexOf("-") + 1)));

Personally I find this rather horrible, so it's just for interest!

Dan Diplo
  • 25,076
  • 4
  • 67
  • 89
  • just for readability I'd have put "list.FindAll(s => s.ToCharArray(). Where(c => c == '-').Count() ==2)" all on one line, but thanks, your solution got me thinking about lambdas and delegates. Think I understand them a little better now. – Matt Jacobsen Aug 10 '10 at 11:43