Как оптимизировать этот код?
ParentDoglist, ChildDoglistis - Ilist. dogListBox - окно списка
foreach (Dog ParentDog in ParentDoglist)
{
foreach (Dog ChildDog in ChildDoglist)
{
if(ParentDog.StatusID==ChildDog.StatusID)
dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
}
}
РЕДАКТИРОВАТЬ: ParentDogTypeList, DogTypeList были переименованы в ParentDoglist, ChildDoglist, где оба не связаны друг с другом
if(ParentDog.Key==ChildDog.Key)
был изменен на
if(ParentDog.StatusID==ChildDog.StatusID)
Complete Story:
Мне нужно заполнить раскрывающийся список, который будет отвечать взаимностью Parent Child. Есть определенные собаки, у которых, возможно, нет никакого ребенка, и это назвали бы листвой. И мне также нужно показать количество собак в этой конкретной категории.
DD будет выглядеть как
Parent1
Child11 (10)
Child12 (12)
Parent2
Child21 (23)
Child22 (20)
Leaf1 (20)
Leaf2 (34)
. Таким образом, ParentDoglist объединит все элементы Child и leaf вместе со счетчиком, а ChildDogList, следовательно, будет иметь Parent и ID листьев Я мог бы заполнить соответствующего Ребенка своим Родителем и напрямую связать лист.
Родитель, Ребенок и Собака-Лист будут храниться в одной таблице и различаться по статусу, а количество будет в другой таблице.
Ни у одного из родителей не было бы никакого количества, только у ребенка и листа было бы количество
Таблица схем:
Вы можете сортировать ParentDoglist
и ChildDoglist
и выполнять линейный O(n)
алгоритм поиска вместо этого O (n^2)
.
Но вы можете отсортировать контейнеры в O((ParentDoglist.Size() + ChildDoglist.Size()) * log2(ParentDoglist.Size() + ChildDoglist.Size()))
.
Тогда, если вы запустите этот код ТОЛЬКО ОДИН РАЗ, ваш алгоритм будет оптимальным.
Но если вы ищете БОЛЬШЕ ОДНОГО РАЗА, оптимальным решением является сортировка контейнеров и сравнение за линейное время, но если ваш контейнер может изменяться между запуском функций поиска и вы используете "более одного раза решение», вы должны использовать контейнер RB-Tree для переноса этих элементов, потому что с обычным списком после изменения контейнера вы не можете вернуться в отсортированное состояние в O(log(n))
время.
foreach (var ParentDog in ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.Key== p.Key)).ToList())
dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
Вот как вы это сделаете с LinQ
Ваша самая большая проблема, вероятно, заключается в dogListBox.Items.Add
. Добавлять каждый элемент по одному довольно дорого. ListBox.Items.AddRange
более эффективен.
Чтобы сделать внутренний цикл намного меньше, вы можете создать поиск ключей во внутреннем цикле.
List<ListItem> listItems = new List<ListItem>();
ILookup<string, Dog> childDogsPerKey = ChildDoglist.ToLookup(dog => dog.Key);
foreach (Dog ParentDog in ParentDoglist)
{
foreach (Dog ChildDog in childDogsPerKey[ParentDog.Key])
{
listItems.Add(new ListItem(ParentDog.Name, ParentDog.Key));
}
}
dogListBox.Items.AddRange(listItems.ToArray());
Этот код предполагает, что несколько дочерних собак могут иметь один и тот же ключ. Если для каждого ключа может быть только одна дочерняя собака, вы можете вместо этого использовать .ToDictionary()
Вы можете заменить вложенный цикл foreach простым выражением Linq. Чтобы это работало, вам нужно использовать System.Linq;
foreach (Dog ParentDog in
(from dog in ParentDogList
from ChildDog in dog.StatusId
where dog.StatusId == ChildDog.StatusId)
select dog) )
{
dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
}
Я по-прежнему считаю, что наиболее элегантным и оптимизированным способом является использование для этого Linq.
box.Items.AddRange(
ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.StatusID== p.StatusID))
.Select(r=>new ListItem(r.StatusID, r.Name)).ToArray());
Это все, и это только одна строка. Если вы предпочитаете объединения, вы можете сделать это с помощью этого запроса.
box.Items.AddRange(
ParentDoglist.Join(ChildDoglist, p => p.StatusID, c => c.StatusID, (p,c)=>p)
.Select(r=>new ListItem(r.StatusID, r.Name)).ToArray());