我如何比较两个 IEnumerable<> 对象和 return 一个新对象?

How can I compare two IEnumerable<> objects and return a new one?

我想比较两个 IEnumerable<> 对象和 return 一个新的 IEnumerable<> 对象。

下面是我的代码,其中我有 newFiles 个对象,然后我有 OriginalFiles 个对象。我想比较这两个 IEnumerable<> 对象并找到那些新文件和修改过的文件。

FileConfig class 将每个文件的 md5Hash 值作为字符串,因此我可以比较 md5Hash 上的 OriginalFilesnewFiles 对象字符串找出哪些文件已更改,然后使用这些修改后的文件和新文件创建一个新的 IEnumerable<FileConfig> 对象。

例如:如果newFiles对象总共有10个文件,OriginalFiles有8个文件,这意味着其中有两个新文件。然后剩下的 8 个我将比较并查看使用 md5Hash 字符串更改了哪些文件,所以如果 8 个文件中有 5 个文件发生更改并且还有两个新文件,那么总共我将 return 7 个文件作为 IEnumerable<FileConfig>对象。

public class ProcessFile
{
    public IEnumerable<FileConfig> OriginalFiles { get; set; }


    public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileConfig> newFiles)
    {
        // compare OriginalFiles and newFiles object and return a new IEnumerable<FileConfig> object 
        // which has only those files which are modified or new by comparing on md5Hash string
       foreach (var element1 in newFiles)
        {
            var newFileName = element1.Name;
            var newMd5Hash = element1.MD5Hash;
            foreach (var element2 in this.OriginalFiles)
            {
                var originalFileName = element2.Name;
                var originalmd5Hash = element2.MD5Hash;
                if (newFileName.Equals(originalFileName, StringComparison.InvariantCultureIgnoreCase) && !newMd5Hash.Equals(originalmd5Hash, StringComparison.InvariantCultureIgnoreCase))
                {
                    yield return new FileConfig
                    {
                        Name = newFileName,
                        Timestamp = element1.Timestamp,
                        MD5Hash = newMd5Hash
                    };
                }
            }
        }

    }
}

public class FileConfig
{
    public string Name { get; set; }
    public DateTime Timestamp { get; set; }
    public string MD5Hash { get; set; }
}

我可以 运行 两个 for 循环并比较每个文件的 md5Hash 字符串并找出哪些文件已被修改和 return 新的 IEnumerable<FileConfig> 对象但是在 C# 中有任何快捷方式可以轻松地做同样的事情或任何其他更好的方法吗?

在你的位置我会使用 LinQ。我们也不知道 FileConfig 是什么样的。

此示例 returns 新文件和已更改文件的列表。

我使用了 FileInfo 属性。您的 FileConfig class 可以继承自

public class FileConfig : FileInfo

所以您不会错过那些可比较的属性。

public class ProcessFile
    {
        public IEnumerable<FileInfo> OriginalFiles { get; set; }


        public IEnumerable<FileInfo> GetNewFiles(IEnumerable<FileInfo> newFiles)
        {
            List<FileInfo> result = new List<FileInfo>();
            result.AddRange(newFiles.Where(x => !OriginalFiles.Any(a => a.FullName == x.FullName) || OriginalFiles.Any(a => a.FullName == x.FullName && a.Length != x.Length)));
            return result;

        }
    }

如果您熟悉 LinQ,应该很简单。如果没有,我会建议对其进行一些研究。 https://docs.microsoft.com/cs-cz/dotnet/csharp/tutorials/working-with-linq

如果您有任何问题,我很乐意为您提供帮助。

使用 FileConfig 的 LinQ

public class ProcessFile
    {
        public IEnumerable<FileConfig> OriginalFiles { get; set; }


        public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileInfo> newFiles)
        {
            List<FileConfig> result = new List<FileConfig>();
            result.AddRange(newFiles.Where(x => !OriginalFiles.Any(a => a.Name == x.Name) || OriginalFiles.Any(a => a.Name == x.Name && a.MD5Hash != x.MD5Hash)));
            return result;

        }
    }

仅返回 IEnumerable:

   public class ProcessFile
        {
            public IEnumerable<FileConfig> OriginalFiles { get; set; }
    
    
            public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileInfo> newFiles)
            {
                return newFiles.Where(x => OriginalFiles.Any(a => a.Name != x.Name || (a.Name == x.Name && a.MD5Hash != x.MD5Hash)));
    
            }
        }

您可以使用 LINQ。

public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileConfig> newFiles)
{
    return
    // compare OriginalFiles and newFiles object and return a new IEnumerable<FileConfig> object 
    // which has only those files which are modified or new by comparing on md5Hash string
    from element1 in newFiles
    let newFileName = element1.Name
    let newMd5Hash = element1.MD5Hash
    from element2 in this.OriginalFiles
    let originalFileName = element2.Name
    let originalmd5Hash = element2.MD5Hash
    where newFileName.Equals(originalFileName, StringComparison.InvariantCultureIgnoreCase) && !newMd5Hash.Equals(originalmd5Hash, StringComparison.InvariantCultureIgnoreCase)
    select new FileConfig
    {
        Name = newFileName,
        Timestamp = element1.Timestamp,
        MD5Hash = newMd5Hash
    };
}

在我看来,您需要左外连接来获取新文件的大小写和现有文件的更改。应该这样做:

public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileConfig> newFiles) =>
    from element1 in newFiles
    join element2 in this.OriginalFiles
        on element1.Name.ToLowerInvariant() equals element2.Name.ToLowerInvariant()
        into g
    where !g.Any() || !element1.MD5Hash.Equals(g.First().MD5Hash, StringComparison.InvariantCultureIgnoreCase)
    select new FileConfig
    {
        Name = element1.Name,
        Timestamp = element1.Timestamp,
        MD5Hash = element1.MD5Hash,
    };

如果你做了 FileConfig read-only 那么你可以这样做:

public IEnumerable<FileConfig> GetNewFiles(IEnumerable<FileConfig> newFiles) =>
    from element1 in newFiles
    join element2 in this.OriginalFiles
        on element1.Name.ToLowerInvariant() equals element2.Name.ToLowerInvariant()
        into g
    where !g.Any() || !element1.MD5Hash.Equals(g.First().MD5Hash, StringComparison.InvariantCultureIgnoreCase)
    select element1;