简体   繁体   中英

Returning a list that is filtered based on another list in C#

Im quite new to C# so trying to test a simple string filter but not getting the desired results. This is my test method:

[TestMethod]
    public void Test_ExceptFilter()
    {
        IEnumerable<string> allnames = new List<string>(){"Thumbs.db","~","one","two exe here","three"};
        var u = FileLister.GetFilteredList(allnames, new [] { "thumbs","~"}, false);
    }

I have a static class called FileLister which has the GetFilteredList method, and the bit that is not working is when i try to return a list that DOES NOT CONTAIN any strings that are in the second IEnumerable.

So in my example here, i expect var u to have "one","two exe here" and "three" only, but it has all the items from the allnames list!.

These are the various ways i have tried and in all of them, the part im struggling with is where the boolean includewords is passed in as false:

//Return strings that contain or dont contain any element in the array
    public static IEnumerable<string> GetFilteredList(IEnumerable<string> myfiles,
        IEnumerable<string> filterbythesewords, bool includewords)
    {
        if (includewords)
        {
            return from line in myfiles
                where filterbythesewords.Any(item => line.Contains(item))
                select line;
        }
        else
        {

            return from line in myfiles
                where filterbythesewords.Any(item => !line.Contains(item))
                select line;


        }
    }

SECOND TRIAL

 //Return strings that contain or dont contain any element in the array
    public static IEnumerable<string> GetFilteredList(IEnumerable<string> myfiles,
        IEnumerable<string> filterbythesewords, bool includewords)
    {
        if (includewords)
        {
            return from line in myfiles
                where filterbythesewords.Any(item => line.Contains(item))
                select line;
        }
        else
        {

            List<string> p = new List<string>();
            p.AddRange(myfiles.Except(filterbythesewords));
            return p;


        }
    }

THIRD TRIAL

 //Return strings that contain or dont contain any element in the array
    public static IEnumerable<string> GetFilteredList(IEnumerable<string> myfiles,
        IEnumerable<string> filterbythesewords, bool includewords)
    {
        if (includewords)
        {
            return from line in myfiles
                where filterbythesewords.Any(item => line.Contains(item))
                select line;
        }
        else
        {
           return myfiles.Where(file => filterbythesewords.Any(x => !file.ToUpperInvariant().Contains(x.ToUpperInvariant())));
        }
    }

How can i make this work please? Ultimately i want to be able to filter filenames from a directory listing based on their file extensions or part of their names.

cheers

The problem is that you're using Any with a negative condition - which means you'll include the value if there are any words that aren't included in the candidate. Instead, you want to think of it as:

  • Exclude a file the words if any of the words are included in the file
  • Include a file if all of the words aren't in it.
  • Include a file if "not any" of the words are in it (ie if a positive check isn't true for any of the words)

So you could use:

return myfiles.Where(file => filterbythesewords.All(item => !file.Contains(item));

or

return myfiles.Where(file => !filterbythesewords.Any(item => file.Contains(item));

(There's no need for a query expression here - when you're basically just doing a simple filter, query expressions don't help readability.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM