首页 > 解决方案 > 如何比较两个 IEnumerable<> 对象并返回一个新对象?

问题描述

我想比较两个IEnumerable<>对象并返回一个新IEnumerable<>对象。

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

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

例如:如果newFiles对象总共有 10 个文件并且OriginalFiles有 8 个文件,那么这意味着其中有两个新文件。然后剩下的 8 个,我将比较并查看使用md5Hash字符串更改了哪些文件,所以如果 8 个文件中有 5 个文件更改并且还有两个新文件,那么我将返回 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字符串上的每个文件,并找出哪些文件已被修改并返回新IEnumerable<FileConfig>对象,但是是否有任何快捷方式可以轻松完成相同的事情或在 C# 中以任何其他更好的方式?

标签: c#asp.netlinqienumerable

解决方案


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

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只读,那么您可以这样做:

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;

推荐阅读