以不同的方式在List上使用Contains

时间:2016-06-08 10:49:49

标签: c# .net list sorting contains

我有这个代码,我想改变:

foreach (DirectoryInfo path in currDirs) {

            if (!newDirs.Contains(path)) { 

                MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
                currNoPairs.Add(path);
            }
        }

在If部分,我不想检查路径,我想检查path.Name。 那么我如何在属性上使用Contains方法。 目标是整理当前目录列表和新目录列表列表中名称不同的所有文件夹。

3 个答案:

答案 0 :(得分:1)

以下是检查财产Any

的方法
foreach (DirectoryInfo path in currDirs) {

            if (!newDirs.Any(dir => dir.FullName == path.FullName)) { 

                MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
                currNoPairs.Add(path);
            }
        }

顺便说一下,你的代码可以用这样的更好的方式编写

var currDirsConcrete = currDirs.ToArray();
var pathsNotFound = "Following paths were not found \r\n " + string.Join("\r\n", currDirsConcrete.Where(d => d.FullName != path.FullName).ToArray());

var pathsFound = currDirsConcrete.Where(d => d.FullName == path.FullName).ToArray();

 MyLog.WriteToLog(pathsNotFound, MyLog.Messages.Warning);

注意:如果currDirs已经是数组或列表,则可以跳过第一行currDirsConcrete。我这样做是为了避免重新确定可枚举的内容。

答案 1 :(得分:1)

请参阅 - IEnumerable<T>.Contains with predicate

那些采用“谓词”(表示匹配的布尔函数)的函数将允许您执行更复杂的检查。在这种情况下,您可以使用它们来比较子属性而不是顶级对象。

新代码看起来像这样:

foreach (DirectoryInfo path in currDirs) {
    if (!newDirs.Any(newDir => newDir.Name == path.Name)) {
        // TODO: print your error message here
        currNoPairs.Add(path.Name);
    }
}

回复你的评论:

  

好的,我明白了,但是,任何和之间的差异是什么呢?

List<T>.Contains

此方法遍历列表中的每个项目,查看该项目是否等于您传入的值。

此方法的代码看起来有点像这样(在此处简化为了说明):

for(var item in yourList) {
    if(item.Equals(itemYouPassedIn) {
        return true;
    }
}

return false;

如您所见,它只能比较顶级项目。除非您使用覆盖默认Equals方法的自定义类型,否则它不会检查子属性。由于您使用的是内置DirectoryInfo类型,因此无法在不创建自定义派生类的情况下覆盖此Equals行为。由于有更简单的方法可以做到这一点,我不推荐这种方法,除非你需要在很多不同的地方进行。

IEnumerable<T>.Any

此方法遍历列表中的每个项目,然后将该项目传递给您传入的“谓词”函数。

此方法的代码看起来有点像这样(为了说明而简化):

for(var item in yourList) {
    if(isAMatch(item)) { // Note that `isAMatch` is the function you pass in to `Any`
        return true;
    }
}

return false;

您的谓词函数可能会像您希望的那样复杂,但在这种情况下,您只需使用它来检查子属性是否相等。

// This bit of code defines a function with no name (a "lambda" function).
// We call it a "predicate" because it returns a bool, and is used to find matches
newDir => newDir.Name == path.Name

// Here's how it might look like if it were defined as a normal function -
// this won't quite work in reality cause `path` is passed in by a different means,
// but hopefully it makes the lambda syntax slightly more clear
bool IsAMatch(DirectoryInfo newDir) {
    return newDir.Name == path.Name;
}

由于您可以在每个使用它的地方自定义此谓词,因此这可能是更好的策略。我推荐这种风格,直到你在代码中的一些地方进行这种精确检查,在这种情况下,自定义类可能会更好。

答案 2 :(得分:0)

我会将linq与except一起使用并实施DirComparator

List<DirectoryInfo> resultExcept = currDirs.Except(newDirs, new DirComparator()).ToList();

此处为IEqualityComparer<DirectoryInfo>

public class DirComparator : IEqualityComparer<DirectoryInfo> {

    public bool Equals(DirectoryInfo x, DirectoryInfo y)
    {

        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the products' properties are equal.
        return x.Name.equals(y.Name);
    }

     public int GetHashCode(DirectoryInfo dir)
    {
        //Check whether the object is null
        if (Object.ReferenceEquals(dir, null)) return 0;

        //Get hash code for the Name field if it is not null.
        return dir.Name == null ? 0 : dir.Name.GetHashCode();
    }
}

如果您想要反过来,也可以使用intersect