IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Dernière occurence dans un ArrayList.


Sujet :

C#

  1. #1
    Membre averti
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 35

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Par défaut Dernière occurence dans un ArrayList.
    Bonjour,

    Je voudrais récupérer l'index de la dernière occurence d'un objet dans un e ArrayList.
    J'ai vu qu'il existait une méthode LastIndexOf, mais je voulais savoir, comment avoir une recherche sur un attribut?

    Je m'explique: il s'agit d'une arraylist d'objets dont j'ai créé la classe. Chacun contient un champ identifiant et un champ "flag" (booléen).
    Je voudrais avoir l'index du dernier objet ayant un flag à false, et je ne peux pas prévoir à l'avance l'identifiant qu'il aura.

    Merci de m'aider

  2. #2
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    Salut,

    Tout simplement :

    MonObjet[] tab est ton array :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int i =0;
     
    while(tab[i].Flag == false)
    {
     i++;
    }
     
    return i;

    i represente la valeur de ton index.

  3. #3
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Salut,
    J'ai rien sous la main pour vérifier ce que je vais dire et donc je serai peut être à coté de la plaque mais bon...

    Je dirais que tu as plusieurs choix :
    - dans ton objet (contenant le flag) tu peux surcharger la méthode Equal. Si je me plante pas cette méthode est appelée lorsque tu fais ton LastIndexOf, donc si tu surcharge pour dire que c'est égal en fonction de l'attribut ca devrais fonctionner.
    - Dans le même esprit il y a une interface IComparable que tu peux implémenté. Je suis moins sur que ca fonctionne, mais tu peux toujours tenter.

    - Le plus simple pour moi (simple != efficace) est de faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(i = MonArrayList.Count - 1; i >= 0; i--)
    EDIT:
    @worm83 : Il a dit le dernier élément de la liste, pas le premier

  4. #4
    Membre Expert Avatar de meziantou
    Homme Profil pro
    autre
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : autre
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    object o = null;
    for(i = MonArrayList.Count - 1; i >= 0; i--)
    {
        if(ta condition)
        {
            o = MonArrayList[i];
            break;
        }
    }
    // o contient le dernier element correspondant à ta condition
    Petite remarque
    Pourquoi ne pas utiliser les collection générique : List<T>
    Si tu utilises dotnet 3.5 il y a Linq ce qui permet d'écrire quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    taList.OfType<TonType>().Last(a => ta condition);

  5. #5
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    L'avantage d'un simple While par rapport a ta solution meziantou c'est que je ne parcourt pas tout le tableau, j'en sort des que j'ai trouve mon objet.
    Celle de ctxnop est equivalente ca dependra de la collection.

  6. #6
    Membre Expert Avatar de meziantou
    Homme Profil pro
    autre
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : autre
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Par défaut
    L'avantage d'un simple While par rapport a ta solution meziantou c'est que je ne parcourt pas tout le tableau, j'en sort des que j'ai trouve mon objet.
    C'est d'ailleur pourquoi j'ai édité mon message...

  7. #7
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    J'avais pas vu, désolé

  8. #8
    Membre averti
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 35

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Par défaut
    Merci!

    J'étais partie pour faire un foreach mais je voulais savoir s'il y avait quelque chose de performant... Car je ne connais pas l'efficacité du Garbage Collector. J'ajoute un élément à la liste toutes les x secondes, et l'appli tourne toute la journée, donc ça peut être long

    Et justement: est-ce que ta solution meziantou ne posera pas de problème si j'ajoute des messages pendant l'exceution de la boucle? (je fais de la programmation multiil va falloir que je bloque la liste?)

  9. #9
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Citation Envoyé par Ed.11 Voir le message
    Et justement: est-ce que ta solution meziantou ne posera pas de problème si j'ajoute des messages pendant l'exceution de la boucle? (je fais de la programmation multiil va falloir que je bloque la liste?)
    La boucle (for ou while) n'est aucunement thread-safe.
    Si tu ne fais qu'ajouter des élément en FIN du arraylist, ca ne posera pas de problème. Par contre, une insertion, une suppression ou une modification d'élément est problématique.
    Donc pour sécuriser il te faudra synchroniser les thread/processus ayant accès à la liste. Si je me plante pas ca se fera par un lock de MonArrayList.SyncRoot.

    Edit:
    Ah oui, une ou deux précisions : je pense pas qu'un foreach puisse lire la liste a l'envers et n'est donc pas la bonne solution.
    De plus un foreach n'autorise aucune modification de la collection (tu ne peux donc ni modifier un élément, ni en ajouter, ni en supprimer, ou même en déplacer, toute tentative provoquera une exception).

    For ou While, les deux sont sensiblement identique. Pas vraiment de différence de perf à ma connaissance. C'est surtout une question d'écriture.
    On utilise plus naturellement le for quand on connait à l'avance le nombre d'itération maximum que l'on va faire (typiquement le parcourt d'une collection dont le nombre d'éléments est donné par Count).
    Le while est plutot utilisé quand la condition dépend d'un calcul/appel qui à lieu à chaque itération. Ex : while (MaForm.IsVisible) { /* */ }
    Dans mon exemple on a aucune idée du nombre d'itération de la boucle.

  10. #10
    Membre Expert Avatar de meziantou
    Homme Profil pro
    autre
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : autre
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Par défaut
    Aucune des collections n'est thread-safe sauf celles qui se trouvent dans l'espace de nom : System.Collections.Concurrent (nouveau dans dotnet 4).

    je pense pas qu'un foreach puisse lire la liste a l'envers
    foreach utilise l'énumerateur de la collection (qui lit généralement les données dans le sens "normal")

    J'avais pas vu, désolé
    Vu ta vitesse de réaction, je n'avais pas encore modifié ma réponse.

  11. #11
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Citation Envoyé par meziantou Voir le message
    foreach utilise l'énumerateur de la collection (qui lit généralement les données dans le sens "normal").
    Oui je sais bien, mais je n'ai jamais vérifié si on pouvais itérer dans le sens inverse comme on peut le faire en C++ sur la STL. C'est pour ca que j'ai dit "je ne pense pas", puisque, n'ayant jamais vérifié, je n'en suis pas sûr. L'énumérateur possède une méthode MoveNext() pout passer à l'objet suivant, mais peut-être possède-t-il également une méthode MovePrevious() ou quelque chose de semblable. Ne l'ayant jamais vu je dirais que non, mais ne l'ayant jamais cherché il est possible que je ne l'ai simplement jamais remarquée.
    D'ailleur tu sembles aussi ne pas en être certains puisque tu utilise le mot "généralement" qui sous-entend qu'il est possible que ce ne soit pas toujours le cas.

  12. #12
    Membre averti
    Inscrit en
    Juillet 2010
    Messages
    30
    Détails du profil
    Informations personnelles :
    Âge : 35

    Informations forums :
    Inscription : Juillet 2010
    Messages : 30
    Par défaut
    D'accord, merci pour ces précisions.

    Le while me semble avoir l'avantage de ne pas dépendre de la longueur de la liste, mais j'ai du mal à voir comment faire pour lire le tableau à l'envers. A contrario, le for me permet de le faire mais le "départ" change toutes les x secondes (à petite échelle ça peut être toutes les 500 ms, mais je ne connais pas la vitesse d'execution du programme).

    Je ferais attention à bien mettre un lock. ca a déja réglé pas mal de mes problèmes...

  13. #13
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Ce n'est pas tout à fait ca.
    Dans ton cas précis il n'y as pas véritablement de différence entre le while et le for.
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    ArrayList MonArrayList = new ArrayList();
    //... Ajout d'éléments MonObjet dans l'arraylist
     
    // Parcourt de la liste à l'envers via un for
    MonObjet obj = null;
    for(int i = MonArrayList.Count - 1; i >= 0; i--) // On part de la fin et on décrémente i jusqu'a i = 0
    {
        MonObjet tmp = (MonObjet)MonArrayList[i];
        if(!tmp.Flag)
        {
            obj = tmp;
            break; // Peut être remplacé par un i = -1 afin de rendre la condition fausse
        }
    }
     
    // Parcourt de la liste à l'envers via un while, totalement équivalent.
    int i = MonArrayList.Count - 1;
    while(i >= 0)
    {
        MonObjet tmp = (MonObjet)MonArrayList[i];
        if(!tmp.Flag)
        {
            obj = tmp;
            break; // Peut être remplacé par un i = -1 afin de rendre la condition fausse
        }
        i--;
    }

    Dans les deux cas en sortie de boucle tu as dans "obj" le dernier élément de la liste dont le flag est a false, ou null s'il n'y en avait pas.
    Ces deux méthodes sont identiques. L'un comme l'autre ne dépendent pas de la longueur de la liste puisque celle-ci est obtenue dynamiquement avant l'entrée dans la boucle.

  14. #14
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    Il existe la SynchronizedCollection<T> si tu veux une liste Thread-Safe, il me semble que tu doit avoir une Factory qui te la fabrique a partir d'une liste passée en argument.

  15. #15
    Membre Expert Avatar de meziantou
    Homme Profil pro
    autre
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : autre
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Par défaut
    Un énumerateur contient seulement deux fonctions MoveNext et Reset donc pas MovePrevious ou autres.
    Le généralement venait du fait que je n'ai jamais vu d'énumérateur par défaut parcourir une liste par la fin. Mais des fois il peut y avoir des esprits tordus...

  16. #16
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Par défaut
    Citation Envoyé par Ed.11 Voir le message
    Je voudrais récupérer l'index de la dernière occurence d'un objet dans un e ArrayList.
    J'ai vu qu'il existait une méthode LastIndexOf, mais je voulais savoir, comment avoir une recherche sur un attribut?

    Je m'explique: il s'agit d'une arraylist d'objets dont j'ai créé la classe. Chacun contient un champ identifiant et un champ "flag" (booléen).
    Je voudrais avoir l'index du dernier objet ayant un flag à false, et je ne peux pas prévoir à l'avance l'identifiant qu'il aura.
    Le mieux que tu puisse faire c'est d'utiliser un collection générique et d'utiliser Linq. Là tu utilises une collection qui n'est pas appropriée à ce que tu en fais. Donc tu vas faire des contorsions qui restent hazardeuses. Il vaut mieux revenir un plan au dessus et utiliser une collection typée

  17. #17
    Membre émérite Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Par défaut
    La tu cerne un autre problème B.AF, mais tu a raison la MSDN préconise l'utilisation de collection Génériques si l'on ne contrôle pas le nombre de données contenues dans le tableau. Qui plus est Linq To Object est magique

  18. #18
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Bah ca n'a rien de tordu de vouloir parcourir une liste depuis sa fin. C'est typiquement ce qui est fait dans le cadre d'une liste FIFO et même d'une stack. C'est bien pour ca qu'on à inventer les listes double-chainées et qu'on peut décrémenter les itérateurs en C++.
    Après, le fait que ce ne soit pas prévu de base dans le framework est une autre histoire et ce n'est de toute façon pas bloquant (cf. les codes ci-dessus).

    Quand à l'utilisation de Linq je ne suis pas convaincu. Je suis tout à fait d'accord pour dire que ca simplifie l'écriture de ce genre de chose (sélection d'un élément dans une liste) mais il cherche avant-tout l'efficacité et je ne suis pas sûr qu'une selection via Linq soit une opération O(n) comme celles qu'on propose.

    Il faut également prendre en compte que sa liste est a priori accessible par plusieurs thread/processus et qu'il est probable qu'il n'ait pas choisit le type. Cependant s'il peut changer le type de sa liste ca ferait pas de mal, (déjà une liste générique éviterai les casts).

  19. #19
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    81
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 81
    Par défaut
    Et pourquoi les fonctions Last() ou First() ... ne répondent pas au besoin ? Je pense que c'est les méthodes les plus optimisées dans ce type de recherche, et en plus avec le typage dynamique du Framework 4.0, j'imagine que tout peut se faire très très simplement sans avoir a faire des for/foreach ... nan ?

    [Edit]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    List<dynamic> laListe = new List<dynamic>();
                for (int i = 0; i < 10; i++)
                    if (i % 2 == 0)
                        laListe.Add(new { Flag = (i%3==0 ? 1 : 0), Test = 45, Id = i });
                    else
                        laListe.Add(new { Flag = (i % 3 == 0 ? 1 : 0), Id = i, AutreVar=45, t2 = "Encore un test" });
     
                foreach (dynamic d in laListe)
                    Console.WriteLine("{0}", d);
     
                dynamic elt = laListe.Last(d => d.Flag == 1);
     
                Console.WriteLine("Dernier élément avec Flag = 1 : ");
                Console.WriteLine(elt);

  20. #20
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Par défaut
    Citation Envoyé par worm83 Voir le message
    La tu cerne un autre problème B.A.F, mais tu a raison la MSDN préconise l'utilisation de collection Génériques si l'on ne contrôle pas le nombre de données contenues dans le tableau.
    Un problème de code qui découle d'un problème de conception n'est pas un problème, il sera résolu avec la résolution du problème de conception.

    Déjà; l'array list, n'est pas trié. (cf entre autres les explications de ctxnop)
    Ce qui veut dire qu'il faut itérer. Or précisemment, itérer c'est ce qui consomme du temps sur des collections importantes.

    Quant à la recommandation c'est faux, depuis le 2.0 Microsoft préconise le recours aux listes typées pour la performance.
    create strongly typed collections that provide better type safety and performance than non-generic strongly typed collections.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
        class Program
        {
     
            public class A
            {
                public bool Prop1
                {
                    get; set;
                }
                public string Prop2
                {
                    get; set;
                }
     
                public static A[] GetThousands()
                {
                    var x = new A[100000];
                    for (int i = 0; i < 100000; i++)
                    {
     
                        x[i] = i%2 == 0 ? new A() {Prop1 = true, Prop2 = "Whatever"}:
                             new A() {Prop1 = false, Prop2 = "And ever"};
     
                    }
                    return x;
                }            
            }
     
     
     
     
            static void Main(string[] args)
            {
                var a1  = A.GetThousands();
                var d1 = DateTime.Now;
                List<A> al1=new List<A>(a1);
                var o1 = al1.Last(x => x.Prop1);
                var d2 = DateTime.Now;
                Console.WriteLine(d2.Subtract(d1).Milliseconds);
                Console.Read();
             }

Discussions similaires

  1. Réponses: 5
    Dernier message: 08/01/2013, 17h56
  2. Compter le nombre d'occurence d'un objet dans un arraylist
    Par florianjoy54 dans le forum Windows Forms
    Réponses: 5
    Dernier message: 09/02/2010, 09h40
  3. [C#] [WinForms] Chercher, effacer dans un ArrayList
    Par stailer dans le forum Windows Forms
    Réponses: 4
    Dernier message: 11/10/2004, 17h26
  4. [JSP][BEAN]Récuperer des Beans dans un ArrayList
    Par Jones dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 30/08/2004, 11h22
  5. recherche du nombre d'occurences dans une table
    Par berry dans le forum Requêtes
    Réponses: 3
    Dernier message: 09/01/2004, 20h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo