Shynchronisation de 2 List<T>

Signaler
Messages postés
34
Date d'inscription
mercredi 26 octobre 2005
Statut
Membre
Dernière intervention
24 septembre 2014
-
Messages postés
34
Date d'inscription
mercredi 26 octobre 2005
Statut
Membre
Dernière intervention
24 septembre 2014
-
Bonjour,

J'ai un petit soucie avec deux listes que je voudrais "synchroniser" (je sais pas si je peu le dire ainsi), je m'explique :

J'ai deux List<T> de la structure suivante

    
    public class ListActions
    {
        public int ID { get; set; }
        public string Action { get; set; }
        public Stopwatch Expire { get; set; }
    }


Je déclare les listes comme ceci :

List<ListActions> ListActions0 = new List<ListActions>();
List<ListActions> ListActions1 = new List<ListActions>();

ListActions0 est la liste que je modifie et ListActions1 est la synchronisation de ListActions0.

Les listes se synchronise bien quand j'ajoute un élément à la ListActions0, mais quand j'en retire un la liste, ListActions1 contiens toujours l'élément que j'ai supprimé.

Comment faire pour supprimer l'élément dans ListActions1 n'apparaissant plus dans ListActions0.

Sachant que je ne peux pas faire une simple copie des listes puisqu'il y a un timer que je déclenche dès qu'un élément apparait dans ListActions1.
Et par conséquent je ne peux pas "écraser" les éléments de la liste ListActions1.

Voici le code qui me fait défaut.

            var SynchroList = ListActions0.Select(LB => new { LB.ID, LB.Action, LB.Expire }).Concat(ListActions1.Select(LB => new { LB.ID, LB.Action, LB.Expire })).GroupBy(x => x.ID);
            ListActions1 = (from LB in SynchroList
                            let _ID = LB.ElementAt(0).ID
                            let _Action = LB.ElementAt(0).Action
                            let _Expire = LB.Count() == 2 ? (LB.ElementAt(1).Expire != null && LB.ElementAt(1).Expire.IsRunning ? LB.ElementAt(1).Expire : new Stopwatch()) : new Stopwatch()
                            select new ListActions
                         {
                             ID = _ID,
                             Action = _Action,
                             Expire = _Expire,
                         }).ToList<ListActions>();


Avez vous une idée sur l'erreur que je commet ?

PS : J'ai simplifié au maximum le code présenté, puisque la structure de la liste est plus complexe que ça. Mais mon code représente bien ma problématique.

6 réponses

Messages postés
16115
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
27 juillet 2021
555
Bonjour,

je n'ai pas encore regardé ton code dans le détail.
Mais je ne comprends pas bien ton besoin.
S'il te faut deux listes synchronisées, ne pourrais tu pas faire tout avec une seule liste?

Ça éliminerait tout problème de synchro.

Cordialement
Messages postés
34
Date d'inscription
mercredi 26 octobre 2005
Statut
Membre
Dernière intervention
24 septembre 2014

Je voudrais bien ^^ mais je peux pas. Comment je gère alors le Timer de la liste ListActions1 (cette liste est gérer par un autre thread). Je vais pas gérer le Timer avec la base de donnée, sa va faire trop d'accès pour pas grand chose. Mais je vais regarder voir si je peu pas simplifier.
Messages postés
16115
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
27 juillet 2021
555
Comme tu concatènes les deux listes, quand tu supprimes un item dans 0, il est encore dans 1, donc il sera dans SynchroList et donc apparaitra dans ta requête LinQ, LB.Count vaudra zéro et tu auras un timer tout neuf.

Je pense qu'il serait plus simple que tu crées une méthode pour l'ajout et une pour la suppression. Je ne sais pas comment tu appelles ta méthode de synchronisation, mais c'est à ce moment que tu dois router vers la bonne méthode, et avec l'item à synchroniser en paramètre ça devrait encore être plus simple.

Quelque chose comme ça

        public void SynchroAdd(List<ListActions> ListActions1, ListActions NewItem)
        {
            ListActions1.Add(new ListActions { Action = NewItem.Action, ID = NewItem.ID, Expire = new Stopwatch() });//j'ajoute un clone avec un nouveau timer
        }

        public void SynchroRemove(List<ListActions> ListActions1, ListActions RemoveItem)
        {
            ListActions1.Remove(ListActions1.Find(c => c.ID == RemoveItem.ID));//je supprime l'item qui à le même ID
        }


Et si au moment de router, tu ne sais pas de quel item il s'agit, tu peu retrouver son ID comme ça:
        public static int IdItem(List<ListActions> ListActions0, List<ListActions> ListActions1)
        {
            return ListActions0.Select(c => c.ID).Concat(ListActions1.Select(c => c.ID)).Distinct().First();//je concatène les ID des 2 Listes et je retourne celui qui est unique
        }
Messages postés
34
Date d'inscription
mercredi 26 octobre 2005
Statut
Membre
Dernière intervention
24 septembre 2014

Oui c'est une solution, mais qui ne me satisfait pas encore (dans le pire des cas je l'utiliserais).

Je vais présenter mon problème autrement, sa sera peu être plus simple.
En fait se que je cherche à faire c'est l'équivalent du code suivant mais en Linq.

            List<ListActions> ListActionsTemp = new List<ListActions>();
            for (int i = 0; i < ListActions0.Count; i++)
            {
                if (ListActions1.Any(x => x.ID == ListActions0[i].ID))
                {
                    ListActionsTemp.Add(new ListActions
                    {
                        ID = ListActions0[i].ID,
                        Action = ListActions0[i].Action,
                        Expire = ListActions1.First(x => x.ID == ListActions0[i].ID).Expire
                    });
                }
                else
                {
                    ListActionsTemp.Add(new ListActions
                    {
                        ID = ListActions0[i].ID,
                        Action = ListActions0[i].Action,
                        Expire = new Stopwatch()
                    });
                }
            }
            ListActionsTemp.Clear();
            ListActions1 = ListActionsTemp.ToList();


Je vais détailler ....
Si dans ListActions1 je trouve l'ID qui est présent dans ListActions0, je copie ID et Action dans ListActionsTemp, MAIS conserve le Expire de ListActions1.
Et si, bien sur, je ne trouve pas de correspondance j'ajoute l'objet de ListActions0 dans ListActionsTemp avec un timer tout neuf.
Et pour finir je supprime tous les éléments de ListActions1 et fait la copie de ListActionsTemp dans ListActions1.

Je pense que c'est possible en Linq, mais mes connaissances dans se domaine sont un peu limité. J'ai beau retourné le site de Microsoft http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b dans tous les sens, je ne trouve pas mon bonheur.
Messages postés
16115
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
27 juillet 2021
555
Bonsoir si ce code marche, ne cherche pas plus!
Non sérieusement, il y a aussi des boucles derrière Linq.
Je ne sais pas ce qui est le mieux en temps d'exécution.

Il me semble que les codes que je t'ai donné font à peu près ce que tu veux, sans recréer une liste à chaque fois.
Messages postés
34
Date d'inscription
mercredi 26 octobre 2005
Statut
Membre
Dernière intervention
24 septembre 2014

Je suis adepte de la technique du "code le plus court" ^^, donc je pensais que le code que j'ai précédemment posté pouvais se faire facilement en Linq. Mais comme j'ai pas envie de passer trois jours sur se problème, je vais utiliser cette dernière fonction jumelé avec ton code. Merci encore pour ton aide.