Problème:
J'ai un wpf DataGrid , qui est lié à une liste d'objets de ma classe de modèle personnalisée. Je dois remplir les conditions suivantes:
Je recherche quelque chose de similaire à cette question , mais j'ai du mal à convertir ma liste en quelque chose qui serait compatible avec la méthode Enumerable.Except .
Voici un petit exemple:
Modèle:
List<MyModel> list = new List<MyModel>(); list.Add(new MyModel(0, "Rodney", "189")); list.Add(new MyModel(1, "Janet", "169")); list.Add(new MyModel(2, "John", "110")); list.Add(new MyModel(3, "Samantha", "160")); list.Add(new MyModel(4, "Daniel", "156")); list.Add(new MyModel(5, "Jack", "89")); list.RemoveAll(x => x.ID == 1); var result = Enumerable.Range(list.Min(m => m.ID), list.Count).Except(list).First(); list.Add(new MyModel(result, "Carolyn", "159")); //Should be 1
Essayer d'ajouter un nouveau modèle avec l'ID gratuit le plus bas à ma liste
public class MyModel
{
public MyModel(int mID, string mName, string mScore)
{
ID = mID;
Name = mName;
Score = mScore;
}
public int ID;
public string Name;
public string Score;
}
Je dois probablement utiliser une sorte d'expressions lambda, comme je devais le faire pour la méthode list.Min () , mais il m'a déjà fallu du temps pour l'obtenir ce droit.
4 Réponses :
Le problème est que vous comparez deux types d'objets différents. Vous souhaitez probablement extraire les identifiants: Enumerable.Range (list.Min (m => m.ID), list.Count) est une énumération d'entiers entre 0 et 5, et lorsque vous utilisez Sauf (liste) code>, la liste est constituée d'objets MyModel . var result = Enumerable.Range(list.Min(m => m.ID), list.Count).Except(list.Select(m => m.ID)).First();
Il est probablement préférable d'utiliser .FirstOrDefault () pour éviter l'exception lorsque l'élément avec x.ID == 0 se trouve être celui qui a été supprimé. Une manipulation est également nécessaire au cas où il n'y aurait pas d'espace (le résultat sera 0).
Pourquoi créer du code compliqué? Vous voulez que le nombre soit supérieur à l'élément le plus bas qui n'existe pas dans la liste
var result = list.Min(m => m.ID); while (list.Any(m => m.ID == result)) result++;
Ce n'est peut-être pas le code le plus rapide, mais au moins il est clair.
Pour développer ce qu'un commentateur a publié, utilisez un SortedList , que vous pouvez utiliser pour suivre les identifiants gratuits. De cette façon, vous n'avez pas à rechercher de lacunes. Lorsque vous ajoutez quelque chose à la liste principale, supprimez le premier entier de la liste libre et utilisez cette valeur comme ID de votre modèle. Lorsque vous supprimez le modèle de la liste principale, ajoutez son identifiant à la liste gratuite.
Je ne veux pas parcourir la liste à chaque fois qu'un nouveau modèle est ajouté
En fait, cela signifie que vous ne pouvez pas utiliser les méthodes Linq comme
Min,MaxetSaufcar elles parcourent votre collection sous le capot.Une autre chose que vous devez garder à l'esprit est que
RemoveAllparcourt également tous les éléments de la liste. Vous devez donc changer deux choses: la première (déjà mentionnée dans le commentaire Fabjan et dans la réponse du Kit) est de suivre tous les identifiants supprimés dansSortedListet la seconde est d'utiliser unDictionarypour supprimer votre modèle par clé, ce qui est de complexitéO (1)au lieu deO (N)dans le cas deList.Vous pouvez encapsuler cette logique avec la classe
Containersuivante:public class Container { private readonly Dictionary<int, MyModel> items = new Dictionary<int, MyModel>(); private readonly SortedList removedIds = new SortedList(); private int maxId = 0; public int Add(MyModel model) { int id; if (removedIds.Count > 0) { id = (int) removedIds.GetByIndex(0); removedIds.RemoveAt(0); } else { id = maxId++; } model.ID = id; items.Add(id, model); return id; } public void RemoveById(int id) { if (!items.ContainsKey(id)) throw new ArgumentException(); // or just return items.Remove(id); removedIds.Add(id, id); } }
Vous voudrez peut-être jeter un œil sur Collection SortedList
Une réponse générale à votre question peut être intéressante, mais il y a des indices que vous y réfléchissez peut-être trop. Pourquoi ne voulez-vous pas parcourir une petite liste à chaque fois qu'elle change? À quelle fréquence change-t-il? Itérer sur de petites collections (<100 éléments) est souvent plus rapide que des approches plus intelligentes. Et même si ce n'est pas le cas, vous devez vous demander si le fait d'être intelligent en vaut la peine.
@TKK la petite liste n'est qu'un exemple. Je ne sais pas quelle sera la taille des listes (en fait, la liste actuelle contient déjà plus de quelques centaines d'entrées), mais je suis chargé de créer une méthode générale à utiliser pour remplir toutes les listes de notre application.