-1

What is the differences between a regular search algorithm with comparison variables and one made with the lambda operators?

What are they doing differently internally and how would you describe it as simple as possible? Both versions are giving the same output to the user.

//LINQ: 
Console.WriteLine("Search for a word: ");
string userInput = Console.ReadLine();
var entries = logbook.Where(entry => entry.Any(item =>item.IndexOf(userInput, StringComparison.OrdinalIgnoreCase) > -1));
foreach (var entry in entries)
{   
    Console.WriteLine(string.Join(", ", entry));    
}
break;

//Regular foreach: 
Console.WriteLine("Search for a word: ");

string userInput = Console.ReadLine();
foreach (string[] logs in logbook)
{
    if (logs[0] == userInput)
        Console.WriteLine("Word found!\n\nTitle: " + logs[0] + "\nText: " + logs[1] + "\n");
    else if (logs[1] == userInput)
        Console.WriteLine("Word found!\n\nTitle: " + logs[0] + "\nText: " + logs[1]);
}
  • It would really help if you'd give us comparable pieces of code - your second piece of code doesn't use `keyword` at all for example, and the first piece of code asks for `userInput` but then ignores it, which suggests you probably *meant* to use `userInput` instead of `keyword`... but that this isn't code you've actually tested. Likewise your second piece of code performs a completely different comparison to the first piece of code. – Jon Skeet Nov 19 '17 at 18:57
  • (If you edit the question to make the pieces of code more comparable, please take care over formatting - I reformatted it so that it's more readable, please do likewise if you edit.) – Jon Skeet Nov 19 '17 at 18:58
  • 1
    Your question is not really defined well.... What is the difference?.. What if instead of 2 strings in the nested array you have 100? then the second version is not likely to be what you are looking for. Also the outputs are different.. So basically what two cases you want to compare? and compare in what parameters? Performance/memory/readability/extensibility... – Gilad Green Nov 19 '17 at 18:58
  • @GiladGreen Sorry, my question was more broad as the two just was as an example. when i use the code i can search with both on strings inside an array inside an list. I was just curious how the lambda one differs from a regular for each in this case. – David Lars Nov 19 '17 at 19:05
  • But the examples still do different things... They will maybe both find the same items but the prints will be different. – Gilad Green Nov 19 '17 at 19:06
  • @JonSkeet I have now edited it, thanks for noticing it. it was supposed to be userInput. – David Lars Nov 19 '17 at 19:07
  • The "regular" option will fail under lots of circumstances that the first one handles far better: logbooks with less than 2 log entries, logbooks where an entry that matches the input occurs in position 2 or greater, logbooks where multiple entries match the input. But it definitely won't produce the same output, as it always only ever displays both entries 0 and 1, with explicit labels for each. If you really do mean for a logbook entry to consist of a "Title" and a "Text" field, then I'd recommend you define a class with these fields instead of using an array. – Dylan Nicholson Nov 19 '17 at 19:08
  • 1
    You've still left the code doing *completely* different things though. There's no point in asking which version is clearer when they'll give different results in so many cases. – Jon Skeet Nov 19 '17 at 19:12

1 Answers1

0

I hope you are ready to read some code. I have changed your code so it is comparable.

foreach version

Here is the version of code using foreach:

public static void Main()
{
    Console.WriteLine("Using foreach");
    string userInput = "1";
    var logbook = new List<string[]> { new string[] { "1", "2" } };
    foreach (string[] logs in logbook)
    {
        if (logs[0] == userInput)
            Console.WriteLine("Word found!\n\nTitle: " + logs[0] + "\nText: " + logs[1] + "\n");
        else if (logs[1] == userInput)
            Console.WriteLine("Word found!\n\nTitle: " + logs[0] + "\nText: " + logs[1]);
    }
}

And here is what the compiler generates for the above code:

public static void Main()
{
    Console.WriteLine("Using foreach");
    string b = "1";
    List<string[]> list = new List<string[]>();
    List<string[]> arg_2F_0 = list;
    string[] expr_1F = new string[2];
    expr_1F[0] = "1";
    string[] expr_27 = expr_1F;
    expr_27[1] = "2";
    arg_2F_0.Add(expr_27);
    List<string[]> list2 = list;
    List<string[]>.Enumerator enumerator = list2.GetEnumerator();
    try
    {
        while (enumerator.MoveNext())
        {
            string[] current = enumerator.Current;
            bool flag = current[0] == b;
            if (flag)
            {
                string[] expr_64 = new string[5];
                expr_64[0] = "Word found!\n\nTitle: ";
                string[] expr_6C = expr_64;
                expr_6C[1] = current[0];
                string[] expr_73 = expr_6C;
                expr_73[2] = "\nText: ";
                string[] expr_7B = expr_73;
                expr_7B[3] = current[1];
                string[] expr_82 = expr_7B;
                expr_82[4] = "\n";
                Console.WriteLine(string.Concat(expr_82));
            }
            else
            {
                bool flag2 = current[1] == b;
                if (flag2)
                {
                    Console.WriteLine("Word found!\n\nTitle: " + current[0] + "\nText: " + current[1]);
                }
            }
        }
    }
    finally
    {
        ((IDisposable)enumerator).Dispose();
    }
}

Lambda Version

Here is the version of your code using lambda:

public static void Main()
{
    Console.WriteLine("Using lambda");
    string userInput = "1";
    var logbook = new List<string[]> { new string[] { "1", "2" } };
    var entries = logbook.Where(entry => entry.Any(item => item.IndexOf(userInput, StringComparison.OrdinalIgnoreCase) > -1));
    foreach (var entry in entries)
    {
        Console.WriteLine(string.Join(", ", entry));
    }
}

And here is what the compiler generates for the above code. Please pay attention to the private class with the attribute CompilerGenerated in code below:

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public string userInput;

    public Func<string, bool> <>9__1;

    internal bool <Main>b__0(string[] entry)
    {
        IEnumerable<string> arg_20_0 = entry;
        Func<string, bool> arg_20_1;
        if ((arg_20_1 = this.<>9__1) == null)
        {
            arg_20_1 = (this.<>9__1 = new Func<string, bool>(this.<Main>b__1));
        }
        return arg_20_0.Any(arg_20_1);
    }

    internal bool <Main>b__1(string item)
    {
        return item.IndexOf(this.userInput, StringComparison.OrdinalIgnoreCase) > -1;
    }
}

public static void Main()
{
    Program.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.<>c__DisplayClass0_0();
    Console.WriteLine("Using lambda");
    <>c__DisplayClass0_.userInput = "1";
    List<string[]> list = new List<string[]>();
    List<string[]> arg_3A_0 = list;
    string[] expr_2A = new string[2];
    expr_2A[0] = "1";
    string[] expr_32 = expr_2A;
    expr_32[1] = "2";
    arg_3A_0.Add(expr_32);
    List<string[]> source = list;
    IEnumerable<string[]> enumerable = source.Where(new Func<string[], bool>(<>c__DisplayClass0_.<Main>b__0));
    IEnumerator<string[]> enumerator = enumerable.GetEnumerator();
    try
    {
        while (enumerator.MoveNext())
        {
            string[] current = enumerator.Current;
            Console.WriteLine(string.Join(", ", current));
        }
    }
    finally
    {
        if (enumerator != null)
        {
            enumerator.Dispose();
        }
    }
}

If you pay attention to the code in the Main method, it utilizes the compiler generated class to do its work.

I used SharLab to do the above work.

CodingYoshi
  • 25,467
  • 4
  • 62
  • 64