Как сравнить два объекта IEnumerable <> и вернуть новый? - PullRequest
0 голосов
/ 03 августа 2020

Я хочу сравнить два объекта IEnumerable<> и вернуть новый объект IEnumerable<>.

Ниже мой код, где у меня есть объект newFiles, а затем - объект OriginalFiles. Я хочу сравнить эти два объекта IEnumerable<> и найти те файлы, которые являются новыми файлами, а также имеют измененные файлы.

FileConfig класс имеет md5Hash значение каждого файла в виде строки, поэтому я могу сравнить OriginalFiles и newFiles в строке md5Hash, чтобы выяснить, какие файлы были изменены, а затем создать новый объект IEnumerable<FileConfig> с этими измененными файлами + новыми файлами.

Например: если у объекта newFiles всего 10 файлов, а у OriginalFiles 8 файлов, это означает, что в нем есть два новых файла. И затем оставшиеся 8 я сравню и посмотрю, какие файлы были изменены, используя строку md5Hash, поэтому, если 5 файлов изменились из 8 и было два новых файла, итого я верну 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#?

Ответы [ 3 ]

1 голос
/ 03 августа 2020

Мне кажется, что вам нужно левое внешнее соединение, чтобы получить регистр новых файлов и изменение существующего. Это должно сделать это:

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;
1 голос
/ 03 августа 2020

на вашем месте я бы использовал LinQ. Также мы не знаем, на что похож FileConfig .

Этот пример возвращает список новых и измененных файлов.

Я использовал свойства FileInfo. Ваш класс FileConfig может быть унаследован от него с помощью

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

Если у вас есть какие-либо вопросы, я буду рад вам помочь.

LinQ с FileConfig

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)));
    
            }
        }
0 голосов
/ 03 августа 2020

Вы можете использовать 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
    };
}
...