6
votes

Comment signaler des progrès sur un long appel à .distinct () en C #

J'ai un tableau d'objets personnalisés nommés analyseResult . Le tableau peut contenir des centaines de milliers d'objets; Et, parfois, je n'ai besoin que des éléments distincts () de ce tableau. Donc, j'ai écrit une classe de comparaison de l'article appelée analyseRestitTemComComPalcomparer et faire mon appel comme celui-ci: XXX

Mon problème Voici que cet appel peut prendre beaucoup de temps (sur le ordre de minutes) lorsque le tableau est particulièrement important (supérieur à 200 000 objets).

J'appelle actuellement cette méthode dans un ouvrier d'arrière-plan et affiche un gif de filage pour alerter l'utilisateur que la méthode est effectuée et que l'application n'a pas gelé. Tout cela va bien et bien, mais cela ne donne à l'utilisateur aucune indication de la progression actuelle.

J'ai vraiment besoin d'indiquer à l'utilisateur l'avancement actuel de cette action; Mais je n'ai pas été incapable de trouver une bonne approche. Je jouais avec faire quelque chose comme ceci: xxx

mais le problème est que je n'ai aucun moyen de savoir quel est mon progrès réel. Les pensées? Suggestions?


1 commentaires

Le problème que je pense que vous allez avoir, c'est que vous auriez besoin de savoir combien de valeurs distinctes vous avez à l'avance afin de définir la valeur max de l'indicateur de progression. Bien sûr, vous ne saurez pas cette valeur jusqu'à ce que votre requête ait réellement couru ... vous pouvez toujours essayer d'accélérer ce processus en utilisant un parallalisme (pas sûr de votre cadre) msdn.microsoft.com/en-us/library/dd383943.aspx


3 Réponses :


4
votes

n'appelle pas toarray () code> à la fin de votre méthode, il suffit d'utiliser retour de rendement code>. Donc, cela:

Dictionary<Key, Value> distinctItems = new Dictionary<Key, Value>(); 

foreach (var item in nonDistinctSetOfItems) {
    if (distinctItems.ConatainsKey(item.KeyProperty) == false) {
        distinctItems.Add(item.KeyProperty, item);
    }
}

... = distinctItems.Values // This would contain only the distinct items.


3 commentaires

Merci pour les informations sur l'approche de Jon pour obtenir des objets distincts. Le mien est similaire mais c'est mieux. :-)


J'accepte cette réponse pour trois raisons. 1) Vous avez fourni trois approches pour déterminer des éléments distincts. 2) Alors que les deux premières approches donnent les éléments distincts, ils n'entraînent pas pour déterminer le "progrès"; Mais, la troisième approche me permet de savoir où nous sommes en train de tirer les éléments distincts. 3) J'ai eu la tête de la tête sombre et je n'ai même pas pensé à faire quelque chose d'aussi simple que la troisième approche.


Hey, très apprécié. Mais oui, alors que de nouveaux outils sont cool, il est bon de se rappeler que les techniques classiques sont classiques pour une raison!



1
votes

Compte tenu de la conception de cette méthode distincte, vous itération sur toute la collection chaque fois que vous appelez distinct. Avez-vous envisagé d'écrire une collection personnalisée qui ajoute à un index chaque fois que vous ajoutez un objet au tableau?


2 commentaires

Approche intéressante. Je devrais garder des références au tableau original non modifié et à la matrice distincte. Avez-vous des exemples de cela?


Je n'ai pas d'exemple, mais le concept serait d'évaluer sur ajouter plutôt que sur une requête. Si votre comparaison est corrigée, la méthode d'index pourrait utiliser un index de référence pour éviter la duplication. La méthode de retour de rendement de @sircOdedesalot est plus flexible, vous permettant de déterminer la comparaison avec une Lambda au moment de la conception.



0
votes

D'autre part, vous pouvez utiliser ThreadPool et WAITHANDLE pour exécuter votre entreprise "distincte" et "DisplayProgress" avec plusieurs threads.

public class Sample
{
    public void Run()
    {
        var state = new State();
        ThreadPool.QueueUserWorkItem(DoWork, state);
        ThreadPool.QueueUserWorkItem(ShowProgress, state);
        WaitHandle.WaitAll(new WaitHandle[] {state.AutoResetEvent});
        Console.WriteLine("Completed");
    }

    public void DoWork(object state)
    {
        //do your work here
        for (int i = 0; i < 10; i++)
        {
            ((State) state).Status++;
            Thread.Sleep(1000);
        }

        ((State) state).AutoResetEvent.Set();
    }

    public void ShowProgress(object state)
    {
        var s = (State) state;
        while (!s.IsCompleted())
        {

            if (s.PrintedStatus != s.Status)
                Console.WriteLine(s.Status);
            s.PrintedStatus = s.Status;
        }
    }

    public class State
    {
        public State()
        {
            AutoResetEvent = new AutoResetEvent(false);
        }

        public AutoResetEvent AutoResetEvent { get; private set; }
        public int Status { get; set; }
        public int PrintedStatus { get; set; }
        private bool _completed;
        public bool IsCompleted()
        {
            return _completed;
        }
        public void Completed()
        {
            _completed = true;
            AutoResetEvent.Set();
        }
    }
}


0 commentaires