Propriété Liste des objets dans une boucle foreach

c# dapper

Question

Je me demande si remplir une liste d'objets dans un objet peut être fait plus rapidement que ce que je vois quand je l'exécute. Je remplis les listes CABCodes- & CABDetails avec une simple requête en utilisant Dapper avec .ToList ();

Les deux listes sont donc en mémoire, mais l'opération prend environ 20 secondes.

CABCodes: ~ 10 000 objets

CABDetails: ~ 60 000 objets

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

Existe-t-il une méthode beaucoup plus efficace pour y parvenir?

Réponse acceptée

Vous avez le temps algorithmique O (M * N). Le code suivant le rend O (M + N), ce qui est rapide:

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

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

MISE À JOUR: J'ai vérifié qu'il fonctionne sous 110ms, avec 100 codes de séquence différents.

Voici la configuration du test:

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

MISE À JOUR 2: Et vous pouvez le rendre encore plus rapide (environ 20 fois), si cela ne vous dérange pas d'avoir des références aux mêmes listes dans différentes instances de CABCode, et même plus rapidement si vous le faites en parallèle. De cette façon, il fonctionne sous une milliseconde sur mon système à 8 cœurs:

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

Réponse populaire

Linq n'est pas toujours aussi rapide que l'écriture de ses propres boucles avec des instructions if / else. La deuxième chose est que ToList () crée une nouvelle instance d'une liste, ce qui ralentit également vos performances.

Comment est la performance avec ce code:

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;
}

J'ai peut-être commis des erreurs dans le code, car j'ai écrit à la volée.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi