views:

210

answers:

5

I have reproduced my problem in a console app. Following is the code.

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

namespace LinqSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string query = "Maine, Maryland, Massachusetts, M";

            var queries = query.Trim().Split((new[] { "," }), StringSplitOptions.RemoveEmptyEntries);
            string lastQuery = queries[queries.Length - 1].Trim();

            if (queries.Length > 1)
            {
                var remQueries = queries.Take(queries.Length - 1).ToArray();

                string[] suggestions = new string[] {"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", 
            "Mississippi", "Missouri", "Montana"};

                System.Console.WriteLine("Before Except ");

                suggestions.ToList().ForEach(str => { System.Console.WriteLine(str); });

                var unqiueSugs = from sug in suggestions
                                 where !remQueries.Any(q => q.Equals(sug, StringComparison.OrdinalIgnoreCase))
                                 select sug;

                if (unqiueSugs != null)
                {
                    suggestions = unqiueSugs.ToArray();
                }

                System.Console.WriteLine("\n After Except ");
                suggestions.ToList().ForEach(str => { System.Console.WriteLine(str); });
            }
        }
    }
}

After the above code, I except suggestions to contain all values except "Maine", "Maryland", "Massachusetts". But it is having 7 values that includes "Maryland", "Massachusetts". Where am I doing wrong? Kindly help.

EDIT: I am using dev studio 2008 with .NET 3.5 sp1. I am using above code in my action method of asp.net mvc

+1  A: 

Works for me:

var remQueries = new[]{"Maine", "Maryland", "Massachusetts"};
var suggestions = new[]{"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana"};
var unqiueSugs = from sug in suggestions
                 where ! remQueries.Any(q => q.Equals(sug, StringComparison.OrdinalIgnoreCase))
                 select sug;
unqiueSugs;
{ "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana" }

Your problem is elsewhere. Also note that if your real lists are bigger, you will probably find Except (with a custom IEqualityComparer) faster.

Matthew Flaschen
Me too. I used `string[] suggestions = {...}` as my declarations.
ChrisF
+8  A: 

After the above code, I except suggestions to contain all values except ....

Then, how about this:

var unqiueSugs = suggestions.Except(remQueries, StringComparer.OrdinalIgnoreCase));

No need to make your live more complicated than necessary

Edit: Added StringComparer.OrdinalIgnoreCase for completeness

Edit: As I said, you have a whitespace problem. Take a closer look at remQueries, there is leading whitespace, like " Maryland" instead of "Maryland"

Just use

suggestions = suggestions.Select(s => s.Trim()).Except(remQueries.Select(s => s.Trim()), StringComparer.OrdinalIgnoreCase).ToArray();

and you'll be fine.

string query = "Maine, Maryland, Massachusetts, M";
var queries = query.Trim().Split((new[] { "," }), StringSplitOptions.RemoveEmptyEntries);

will give you these strings: "Maine", " Mayland", " Massachusetts", " M"

dkson
Answer is crisp. I tried this, but it is also not working. If I check before Except method execution, I see suggestions having 8 and remQueries having 3 values. After executtion, unqiueSugs contains 7 values. Now I am really puzzled.
mohang
No, it's not. My solution works fine, as Matthew's does. Your problem has to be elsewhere. As Eric Lippert suggested, provide a full example of your code. Are you sure there's no typo? Maybe leading/trailing whitespace? Then try something like suggestions.Select(s => s.Trim()).Except(remQueries.Select(s => s.Trim()), StringComparer.OrdinalIgnoreCase));
dkson
+1  A: 

How about

var unqiueSugs = suggestions.Except(remQueries).ToArray();
Winston Smith
A: 

Just a quick observation on the code you have posted but:

        string query = "Maine, Maryland, Massachusetts, M";
        var queries = query.Trim().Split((new[] { "," }), StringSplitOptions.RemoveEmptyEntries);

gives you your 4 strings but they aren't trimmed as you'd expect in my debugger hovering over queries shows: "Maine" " Maryland" " Massachusetts" " M"

(notice the space before the last 3 strings)

I do believe the following code is what you were after for your trim operation:

var queries = query.Split((new[] { "," }), StringSplitOptions.RemoveEmptyEntries).Select(X => X.Trim()).ToArray();
cirons42
+5  A: 

Well, I haven't actually run this, but let's read the code and see what it does.

        string query = "Maine, Maryland, Massachusetts, M"; 

        var queries = query.Trim().Split((new[] { "," }), StringSplitOptions.RemoveEmptyEntries); 

query.Trim() does nothing because Trim removes spaces from the beginning and end of the string, not from the middle of the string.

The split produces an array of {"Maine", " Maryland", " Massachusetts", " M"} which is assigned to queries.

Notice the leading spaces on Maryland and Massachusetts. You haven't stripped off these spaces. This seems wrong.

        string lastQuery = queries[queries.Length - 1].Trim(); 

lastQuery is now "M". The array, queries, remains unchanged.

"lastQuery" is then not ever used. Why is this even in here? This is not necessary to show the bug.

        if (queries.Length > 1) 
        { 
            var remQueries = queries.Take(queries.Length - 1).ToArray(); 

OK, now we have an array {"Maine", " Maryland", " Massachusetts"} which is assigned to remQueries. Again, note the leading spaces.

            string[] suggestions = new string[] {"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",  
        "Mississippi", "Missouri", "Montana"}; 

            System.Console.WriteLine("Before Except "); 

            suggestions.ToList().ForEach(str => { System.Console.WriteLine(str); }); 

            var unqiueSugs = from sug in suggestions 
                             where !remQueries.Any(q => q.Equals(sug, StringComparison.OrdinalIgnoreCase)) 
                             select sug; 

I note that "unique" is misspelled here.

The query is "look at each suggestion. Remove any suggestions that are exactly equal to "Maine", " Maryland", or " Massachusetts". Again, note the leading spaces.

            if (unqiueSugs != null) 

This is unnecessary. The query object will never be null.

            { 
                suggestions = unqiueSugs.ToArray(); 

The query executes. Since "Maine" was on the list, it is filtered out. If " Maryland" was on the list it would be filtered out, but it is not. " Maryland" and "Maryland" are different strings.

            } 

            System.Console.WriteLine("\n After Except "); 
            suggestions.ToList().ForEach(str => { System.Console.WriteLine(str); });
        } 

So the result is correct. I suspect your error is that you believe that "Trim" removes all the spaces from a string. It does not. It removes the spaces from the beginning and end of a string.

You should NOT use Replace to get rid of all the spaces in the string because of course "New York" and "Rhode Island" could be in there and you don't want the spaces removed from them presumably. The correct logic is to do the split on the comma first and then do the trim on all the resulting elements. Don't do the trim first!

Now, what's more important is that you learn how to do this sort of simple program analysis yourself rather than asking the internet every time you have a problem. I recommend learning how to use a debugger. Step through your program carefully and examine every step along the way and compare that against what you think the correct state should be. Listen to quiet doubts. Your brain will tell you when something looks out-of-place, like an unexpected space. Listen to that and track it down. Debugging is a skill like any other; you learn it by practicing.

Eric Lippert
+1 awesome answer!
dkson