Удалить foreach - c # оптимизация кода

Как оптимизировать этот код?

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 листьев Я мог бы заполнить соответствующего Ребенка своим Родителем и напрямую связать лист.

Родитель, Ребенок и Собака-Лист будут храниться в одной таблице и различаться по статусу, а количество будет в другой таблице.

Ни у одного из родителей не было бы никакого количества, только у ребенка и листа было бы количество

Таблица схем:

alt text

7
задан Gopi 31 August 2010 в 12:12
поделиться

5 ответов

Вы можете сортировать ParentDoglist и ChildDoglist и выполнять линейный O(n) алгоритм поиска вместо этого O (n^2).

Но вы можете отсортировать контейнеры в O((ParentDoglist.Size() + ChildDoglist.Size()) * log2(ParentDoglist.Size() + ChildDoglist.Size())).

Тогда, если вы запустите этот код ТОЛЬКО ОДИН РАЗ, ваш алгоритм будет оптимальным. Но если вы ищете БОЛЬШЕ ОДНОГО РАЗА, оптимальным решением является сортировка контейнеров и сравнение за линейное время, но если ваш контейнер может изменяться между запуском функций поиска и вы используете "более одного раза решение», вы должны использовать контейнер RB-Tree для переноса этих элементов, потому что с обычным списком после изменения контейнера вы не можете вернуться в отсортированное состояние в O(log(n)) время.

8
ответ дан 6 December 2019 в 19:30
поделиться
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

-1
ответ дан 6 December 2019 в 19:30
поделиться

Ваша самая большая проблема, вероятно, заключается в 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()

2
ответ дан 6 December 2019 в 19:30
поделиться

Вы можете заменить вложенный цикл 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));
}
0
ответ дан 6 December 2019 в 19:30
поделиться

Я по-прежнему считаю, что наиболее элегантным и оптимизированным способом является использование для этого 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());
2
ответ дан 6 December 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: