【问题标题】:Using Contains on an List in a different way以不同的方式在列表中使用包含
【发布时间】:2016-10-08 14:21:24
【问题描述】:

我有这段代码要更改:

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 方法。 目的是把当前目录列表和新目录列表中所有名称不同的文件夹都整理出来。

【问题讨论】:

    标签: c# .net list sorting contains


    【解决方案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。我这样做是为了避免重新确定可枚举。

    【讨论】:

    • 如果 dir 是路径,dir.Name 怎么能等于路径? :/ sry 我是新的,我可能在 Linq 和 lambda 上弄错了
    • @Ams1 DirectoryInfo 对象包含名为 Name 和 Full Name 的属性,实际上我认为您想使用 Full Name。让我更新
    【解决方案2】:

    见 - 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);
        }
    }
    

    回复您的评论:

    好的,我明白了,但是 any 和 contains 之间的区别是什么?

    List&lt;T&gt;.Contains

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

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

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

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

    IEnumerable&lt;T&gt;.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;
    }
    

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

    【讨论】:

    • 好的,我明白了,但是 any 和 contains 之间的区别是什么?
    • @Ams1 尝试编辑以详细回答您的问题。如果仍然令人困惑,请随时发表评论:)
    • 你,先生是我的上帝! :D 谢谢
    【解决方案3】:

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

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

    这里是IEqualityComparer&lt;DirectoryInfo&gt;

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-10
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多