как избежать вложенности для l oop чтобы решить нижеприведенную проблему - PullRequest
0 голосов
/ 12 марта 2020
public class job
    {
        public int Id { get; set; }
        public string JobNumber { get; set; }
        public bool IsValid { get; set; }
    }  

 public class attachment
    {
        public string JobNumber { get; set; }
        public int id { get; set; }

    }

        List<job> joblist = new List<job>();
        List<attachment> attachments = new List<attachment>();

        for (int i = 0; i < joblist.Count; i++)
        {
            for (int j = 0; j < attachments.Count; j++)
            {
                if(joblist[i].JobNumber == attachments[j].JobNumber)
                {
                    joblist[i].IsValid = true;
                }
            }
        }

Если и список заданий, и класс списка вложений имеют одинаковый номер задания, мы делаем его действительным, есть ли способ улучшить этот код с помощью linq

Ответы [ 3 ]

2 голосов
/ 12 марта 2020

Используйте Any, чтобы найти вложение с соответствующим JobNumber:

foreach (var j in joblist)
{
    j.IsValid = attachments.Any(a => a.JobNumber == j.JobNumber);
}

Имейте в виду, что это все еще (наихудший случай) O (n²) операция, хотя в среднем немного более эффективная, чем ваш исходный код, потому что ваш l oop не break после поиска совпадения.

1 голос
/ 12 марта 2020

Используя HashSet, вы можете оптимизировать тест, чтобы вложение имело значение O (1), но издержки на создание HashSet были бы полезны, только если у вас очень длинный список вложений или очень длинный список заданий или используйте один и тот же список вложений с множеством разных списков заданий:

var HasAttachment = attachments.Select(a => a.JobNumber).ToHashSet();

for (int i = 0; i < joblist.Count; i++) {
    joblist[i].IsValid = HasAttachment.Contains(joblist[i].JobNumber);
}
0 голосов
/ 12 марта 2020

Это не чистый LINQ, но вы можете обменять joblist.Count перечисления внутреннего l oop и полностью удалить его для одного перечисления attachments ...

HashSet<string> attachmentJobNumbers = new HashSet<string>(
    // A one-time enumeration of attachments to collect its JobNumber values
    attachments.Select(attachment => attachment.JobNumber)
);

for (int i = 0; i < joblist.Count; i++)
{
    joblist[i].IsValid = attachmentJobNumbers.Contains(joblist[i].JobNumber);
}

The HashSet<> позволяет быстро искать, есть ли вложение с конкретным JobNumber. Это предполагает, что не существует эквивалентных JobNumber значений, которые отличаются только регистром; в противном случае вы можете передать StringComparer в перегрузку конструктора HashSet<> ...

HashSet<string> attachmentJobNumbers = new HashSet<string>(
    // A one-time enumeration of attachments to collect its JobNumber values
    attachments.Select(attachment => attachment.JobNumber),
    StringComparer.OrdinalIgnoreCase
);

..., чтобы получить поиск без учета регистра.

(Из @ ответа NetMage Я узнал, что с 1025 года используется метод расширения ToHashSet(). NET 4.7.2 /.NET Core 2.0, так что будет удобной альтернативой.)

Чистый LINQ способ сделать то же самое будет с ToDictionary() ...

// A one-time enumeration of attachments to collect its JobNumber values
Dictionary<string, attachment> attachmentsByJobNumber = attachments.ToDictionary(attachment => attachment.JobNumber);

for (int i = 0; i < joblist.Count; i++)
{
    joblist[i].IsValid = attachmentsByJobNumber.ContainsKey(joblist[i].JobNumber);
}

... или ToLookup(), хотя любой из них позволяет вам получить attachment по JobNumber, когда attachment здесь не нужен, просто ответ bool ean на «Есть ли вложение с этим JobNumber или нет? " Я думаю, что HashSet<> будет лучше представлять этот вариант использования.

Кроме того, имейте в виду, что. NET правила именования требуют типов и properties для использования Pascal case, поэтому вы должны использовать Job, Attachment и Id (или, возможно, ID) соответственно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...