Lista de relleno propiedad de objetos en un foreach-loop

c# dapper

Pregunta

Me pregunto si completar una lista de objetos en un objeto se puede hacer más rápido de lo que veo cuando lo ejecuto. Lleno las listas CABCodes- & CABDetails-lists con una consulta simple usando Dapper con .ToList ();

Entonces ambas listas están en la memoria, sin embargo, la operación foreach toma alrededor de 20 segundos.

CABCodes: ~ 10,000 objetos

CABDetalles: ~ 60,000 objetos

List<CABCode> CABCodes = new List<CABCode>();
List<CABDetail> CABDetails = new List<CABDetail>();

public class CABCode {
    public int Sequence { get; set; }
    public string Code { get; set; }
    public int Group { get; set; }
    public List<CABDetail> Details { get; set; }
}
public class CABDetail {
    public int CABSequence { get; set; }
    public int Proptype { get; set; }
    public string Propvalue { get; set; }
}

foreach (var c in this.CABCodes) {
    c.Details = this.CABDetails.Where(x => x.CABSequence == c.Sequence).ToList();
}

¿Hay un método mucho más eficiente para lograr esto?

Respuesta aceptada

Tienes O (M * N) tiempo algorítmico. El siguiente código lo convierte en O (M + N), que es rápido:

var cabDetailsBySequence = CABDetails.ToLookup(d=>d.CABSequence);

foreach (var c in this.CABCodes) {
    c.Details = cabDetailsBySequence[c.Sequence].ToList();
}

ACTUALIZACIÓN: he comprobado que funciona en 110 ms, con 100 códigos de secuencia diferentes.

Aquí está la configuración de prueba:

CABCodes = Enumerable.Range(0, 10000).Select(i=>new CABCode{Sequence = i%100}).ToList();
CABDetails = Enumerable.Range(0, 60000).Select(i=>new CABDetail{CABSequence = i%100}).ToList();

ACTUALIZACIÓN 2: Y puede hacerlo aún más rápido (20 veces aprox.), Si no le molesta tener referencias a las mismas listas en diferentes instancias de CABCode, y aún más rápido si lo hace en paralelo. De esta forma se ejecuta en menos de un milisegundo en mi sistema de 8 núcleos:

var cabDetailListsBySequence = cabDetailsBySequence.ToDictionary(i=>i.Key, i=>i.ToList());

//  foreach (var c in this.CABCodes) {
//      c.Details = cabDetailListsBySequence[c.Sequence];
//  }   

this.CABCodes.AsParallel().ForAll(c=>c.Details = cabDetailListsBySequence[c.Sequence]);

Respuesta popular

Linq no siempre es tan rápido como escribir sus propios bucles con sentencias if / else. Lo segundo es que ToList () crea una nueva instancia de una lista, lo que también ralentiza su rendimiento.

Cómo es el rendimiento con este código:

foreach (var c in this.CABCodes) 
{
  var detailList = new List<CABDetail>();
  foreach(var d in CAPDetails)
  {
    if (d.CABSquence == c.Sequence)
    {
      detailList.Add(d);
    }
  }
  c.Details = detailList;
}

tal vez he cometido algunos errores en el código, porque escribí sobre la marcha.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué