2010-08-31 21 views
7

¿Cómo optimizar este código?Eliminar foreach - C# código-optimización

ParentDoglist, ChildDoglistis - Ilist. dogListBox - Cuadro de lista

foreach (Dog ParentDog in ParentDoglist) 
{ 
foreach (Dog ChildDog in ChildDoglist) 
{ 
    if(ParentDog.StatusID==ChildDog.StatusID) 
    dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key)); 
} 
} 

EDIT: ParentDogTypeList, DogTypeList fueron renombrados como ParentDoglist, ChildDoglist, donde ambos no están relacionados entre sí

if(ParentDog.Key==ChildDog.Key) 

fue cambiado a

if(ParentDog.StatusID==ChildDog.StatusID) 

Historia completa:

Necesito rellenar un menú desplegable que correspondería a una relación de Parent Child. Hay ciertos perros que pueden no tener ningún hijo y que se llamarían leafdog. Y también necesito para mostrar el número de perros en esa categoría en particular

DD se vería como

Parent1 
    Child11 (10) 
    Child12 (12) 
Parent2 
    Child21 (23) 
    Child22 (20) 
Leaf1 (20) 
Leaf2 (34) 

Así, el ParentDoglist traería todos los elementos secundarios y de la hoja junto con el conteo y ChildDogList tendría la ID de padre y hoja, por lo tanto, podría poblar el Niño respectivo con su Padre y enlazar la hoja directamente.

El padre, el hijo y el perro hoja se mantendrían en una tabla y se diferenciarían por el valor de estado y el recuento estaría en otra tabla.

Ningún padre tendría ningún recuento, hijo único y hoja tendrían recuento

esquema de la tabla:

alt text

+1

¿Qué línea es lenta? –

+1

¿DogTypeList es una lista de todos los tipos de perros y ParentDogTypeList es un subconjunto de tipos de perros? – gkrogers

+0

@gkrogers Pl mira mi edición –

Respuesta

8

se puede ordenar ParentDoglist y ChildDoglist y hacer lineal O(n) encontrar insead algoritmo de esto O(n^2).

Pero puede ordenar los contenedores en O((ParentDoglist.Size() + ChildDoglist.Size()) * log2(ParentDoglist.Size() + ChildDoglist.Size())).

Entonces, si se ejecuta este código UNA VEZ, el algoritmo es óptimo . Pero si está buscando MÁS DE UNA VEZ, la solución óptima es ordenar los contenedores y hacer la comparación en tiempo lineal, pero si el contenedor puede cambiar entre funciones de búsqueda fue lanuched y usted usando "más de una vez solución de tiempo" debe usar RB-Tree contenedor para transportar estos elementos, porque con la lista normal después de cambiar el contenedor no puede volver al estado ordenado en O(log(n)) vez.

-1
foreach (var ParentDog in ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.Key== p.Key)).ToList()) 
    dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key)); 

así es como usted lo haría con LinQ

+0

¿Todavía no tiene un bucle anidado implícito? –

+0

Esto sigue siendo O (n^2) ;-(solo con foreach perezoso en el contenedor ChildDoglist sin ninguna optimización. – Svisstack

2

Su mayor problema es probablemente la dogListBox.Items.Add. Agregar cada elemento de uno en uno es bastante caro. ListBox.Items.AddRange es más eficiente.

Para hacer que el bucle interno sea mucho más pequeño, puede crear una búsqueda de las teclas en el bucle interno.

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()); 

Este código asume que varios perros niños pueden tener la misma llave. Si solo puede haber un perro hijo por llave, puede usar .ToDictionary() en su lugar

+0

Estoy de acuerdo con que AddRange probablemente ayude mucho. –

1

Dado que esto proviene de la base de datos, es probable que los viajes de ida y vuelta a la base de datos sean un factor determinante del rendimiento. También la comparación ParentDog.Key==ChildDog.Key se puede hacer en SQL, por lo que no extrae toda esa información en su aplicación solo para descartarla.

Rediseña esto para que hagas una única selección para captar todos los datos en una consulta.

Albin mencionó AddRange, pero incluso puede llevar esto un paso más allá y virtualizar su cuadrícula, de modo que solo tira de las filas que se muestran al usuario cuando está mirando esa parte de la cuadrícula.

EDITAR

Para generar la lista que aparece necesita devolver algo como esto de la BD:

 
Parent1, null, null 
Parent1, Child1, 110 
Parent1, Child12, 12 
Parent2, null, null 
Parent2, Child21, 23 
Parent2, Child22 ,20 
Leaf1, null, 20 
Leaf2, null, 34 

Esto parece que necesita algún tipo de left join y una count, con una potencial union all arrojado.

+0

Edité mi pregunta para explicar el completo sceanrio –

+0

sí exactamente pero ¿cómo hacerlo? llene el cuadro de lista sin ningún bucle? –

+0

@Sri, una sola consulta y un solo bucle, no puedo ayudar más sin un esquema de tabla y el sabor SQL que está utilizando (suponiendo SQL Server) –

1

No es el foreach el que tarda en agregar y representar nuevos elementos.

Agregar BeginUpdate/EndUpdate:

dogListBox.BeginUpdate(); 
foreach (Dog ParentDog in ParentDoglist) 
{ 
foreach (Dog ChildDog in ChildDoglist) 
{ 
    if(ParentDog.Key==ChildDog.Key) 
    dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key)); 
} 
} 
dogListBox.EndUpdate(); 
2

sigo pensando que la forma más elegante y optimizado es utilizar LINQ para ello.

box.Items.AddRange(
    ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.StatusID== p.StatusID)) 
    .Select(r=>new ListItem(r.StatusID, r.Name)).ToArray()); 

Eso es todo y es solo una línea. Si prefiere uniones, puede hacerlo con esa consulta.

box.Items.AddRange(
    ParentDoglist.Join(ChildDoglist, p => p.StatusID, c => c.StatusID, (p,c)=>p) 
    .Select(r=>new ListItem(r.StatusID, r.Name)).ToArray()); 
0

Puede reemplazar el bucle foreach anidado con una expresión Linq simple. Para que esto funcione, debes usar 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)); 
}