#c# #linq #search
#c# #linq #Поиск
Вопрос:
например, у меня есть класс, подобный приведенному ниже :
public class MasterRecord
{
public int Id { get; set; }
public string UniqueId{ get; set; }
}
public class DetailRecord
{
public int Id { get; set; }
public int MasterRecordId { get; set; }
public string UniqueId{ get; set; }
}
и я также перечисляю 2, которые:
masterList и DetailList
В masterList будет около 300 000 записей, в DetailList — около 7 000 000 записей
Что мне нужно, так это выполнить цикл для каждой записи в главном списке и выполнить поиск записей с одинаковым именем в DetailList.
Вот мой код :
foreach (var item in MasterList)
{
var matchPersons = DetailList.Where(q => q.UniqueId == item .UniqueId).ToList();
if (matchPersons != null amp;amp; matchPersons.Count() > 0)
{
foreach (var foundPerson in matchPersons)
{
//Do something with foundPerson
foundPerson.MasterRecordId = item.Id;
}
}
}
Сейчас мой код работает очень медленно, каждый поиск обходится мне в 500 миллисекунд, поэтому при 300 тысячах записей на завершение потребуется 2500 минут : ( .
Есть ли какой-либо другой способ ускорить эту функцию?
Спасибо и простите за мой плохой английский.
Обновленный код для того, чтобы сделать более понятным то, что я хочу сделать.
Комментарии:
1. Ваш список поступает из базы данных?
2. Создание словаря займет время, но такое же значительное при выполнении нескольких поисков. Dictionary<строка, персона> dict1 = masterList .GroupBy(x => x.Name , y => y) .ToDictionary(x => x.Key, y => y.FirstOrDefault()); Или, если у вас есть несколько пользователей с одинаковыми именами Dictionary<строка, список<Персона>> dict2 = masterList .GroupBy(x => x.Name , y => y) .ToDictionary(x => x.Key, y => y.ToList());
Ответ №1:
Использование некоторой хэш-структуры было бы одним из лучших вариантов:
var detailLookup = DetailList.ToLookup(q => q.Name);
foreach (var person in MasterList)
{
foreach (var foundPerson in detailLookup[person.Name])
{
//Do something with foundPerson
}
}
Поиск возвращает пустую последовательность, если ключ отсутствует, поэтому вам не нужно его проверять.
Ответ №2:
Вы могли бы использовать объединение по имени.
var result = masterList.Join(detailedList,m=>m.Name,d=>d.Name,(m,d)=>d);
Ответ №3:
Если вам нужно обработать «MasterRecords с их DetailRecords», не используйте обычное соединение, используйте GroupJoin. Это внутренне создаст нечто похожее на таблицу поиска.
Приятно то, что это также будет работать с базами данных, CSV-файлами или любым другим методом, который вы используете для получения ваших записей. Вам не нужно сначала преобразовывать их в списки.
// Your input sequences, if desired: use IQueryable
IEnumerable<MasterRecord> masterRecords = ...
IEnumerable<DetailRecord> detailRecords = ...
// Note: query not executed yet!
// GroupJoin these two sequences
var masterRecordsWithTheirDetailRecords = masterRecord.GroupJoin(detailRecords,
masterRecord => masterRecord.Id, // from masterRecord take the primary key
detailRecord => detailRecord.MasterRecordId // from detailRecord take the foreign key
// ResultSelector: from every MasterRecord with its matching DetailRecords select
(masterRecord, detailRecords) => new
{
// select the properties you plan to use:
Id = masterRecord.Id,
UniqueId = maserRecord.UniqueId,
...
DetailRecords = detailRecords.Select(detailRecord => new
{
// again: select only the properties you plan to use
Id = detailRecord.Id,
...
// not needed, you know the value:
// MasterRecordId = detailRecord.MasterRecordId,
}),
// Note: this is still an IEnumerable!
});
Использование:
foreach(var masterRecord in masterRecordsWithTheirDetailRecords)
{
... // process the master record with its detail records
}
Самое приятное, что вам нужно обработать только некоторые из мастер-записей
(например, после 1000-го вы решаете, что нашли то, что искали),
или, если у вас есть несколько основных записей, из которых вам не нужны все подробные записи, обрабатывается не больше записей, чем необходимо. Linq позаботится об этом
Комментарии:
1. Спасибо за вашу помощь, но в моем случае у меня было 2 таблицы, которые были импортированы уже из другой базы данных. Но по какой-то причине в то время у меня не было внешнего ключа в подробной таблице. Итак, мне нужно запустить эту функцию для сопоставления основной и подробной таблицы вместе с помощью поля уникального идентификатора. Поэтому не уверен, поможет ли ваше решение.