Question

J'ai ce qui est essentiellement un tableau dentelé de paires nom-valeur - je dois générer un ensemble de valeurs nom uniques à partir de ceci. la matrice en dents de scie est d'environ 86 000 x 11 valeurs. Quelle que soit la méthode utilisée pour stocker une paire nom-valeur (une seule chaîne & "; Nom = valeur &"; Ou une classe spécialisée, par exemple KeyValuePair).
Informations complémentaires : il existe 40 noms distincts et un plus grand nombre de valeurs distinctes, probablement dans la région 10 000 valeurs.

J'utilise C # et .NET 2.0 (et les performances sont si médiocres que je pense qu'il est peut-être préférable d'insérer tout mon tableau en dents de scie dans une base de données SQL et de faire une sélection distincte de celle-ci).

Ci-dessous le code actuel utilisé par Im:

List<List<KeyValuePair<string,string>>> vehicleList = retriever.GetVehicles();
this.statsLabel.Text = "Unique Vehicles: " + vehicleList.Count;

Dictionary<KeyValuePair<string, string>, int> uniqueProperties = new Dictionary<KeyValuePair<string, string>, int>();
foreach (List<KeyValuePair<string, string>> vehicle in vehicleList)
{
    foreach (KeyValuePair<string, string> property in vehicle)
    {
        if (!uniqueProperties.ContainsKey(property))
        {
            uniqueProperties.Add(property, 0);
        }
    }
}
this.statsLabel.Text += "\rUnique Properties: " + uniqueProperties.Count;
Était-ce utile?

La solution

Je le fais fonctionner en 0,34 seconde après 9 minutes ou plus

Le problème vient de la comparaison des structures KeyValuePair. J'ai corrigé le problème en écrivant un objet comparateur et en en passant une instance au dictionnaire.

D'après ce que je peux déterminer, KeyValuePair.GetHashCode () renvoie le hashcode de son Key objet (dans cet exemple, l'objet le moins unique).

Lorsque le dictionnaire ajoute (et vérifie l'existence de) chaque élément, il utilise les fonctions Equals et GetHashCode, mais doit compter sur la fonction Equals lorsque le code de hachage est moins unique.

En fournissant une fonction GetHashCode plus unique, la fonction Equals est beaucoup moins utilisée. J'ai également optimisé la fonction Equals pour comparer les valeurs les plus uniques avant les clés moins uniformes.

86 000 * 11 éléments avec 10 000 propriétés uniques s'exécutent en 0,34 secondes à l'aide de l'objet comparateur ci-dessous (sans l'objet comparateur, il faut 9 minutes 22 secondes)

J'espère que cela vous aidera:)

    class StringPairComparer
        : IEqualityComparer<KeyValuePair<string, string>>
    {
        public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
        {
            return x.Value == y.Value && x.Key == y.Key;
        }
        public int GetHashCode(KeyValuePair<string, string> obj)
        {
            return (obj.Key + obj.Value).GetHashCode();
        }
    }

MODIFIER : s'il ne s'agissait que d'une chaîne (au lieu d'un KeyValuePair, où chaîne = Nom + Valeur), le délai serait environ deux fois plus rapide. C’est un problème intéressant, et j’ai passé trop de temps à y consacrer faaaaaar (j’ai cependant appris un peu calme)

Autres conseils

si vous n'avez pas besoin d'une corrélation spécifique entre chaque paire clé / valeur et les valeurs uniques que vous générez, vous pouvez simplement utiliser un GUID? Je suppose que le problème est que votre 'clé' actuelle n'est pas unique dans ce tableau déchiqueté.

Dictionary<System.Guid, KeyValuePair<string, string>> myDict 
   = new Dictionary<Guid, KeyValuePair<string, string>>();


foreach of your key values in their current format
   myDict.Add(System.Guid.NewGuid(), new KeyValuePair<string, string>(yourKey, yourvalue))

On dirait que cela stockerait ce dont vous avez besoin, mais je ne sais pas comment vous en tireriez les données, car il n’y aurait pas de relation sémantique entre le générateur Guid &. ce que vous aviez à l'origine ...

Pouvez-vous fournir plus d'informations dans votre question?

Utilisez KeyValuePair en tant que classe wrapper, puis créez un dictionnaire avec pour créer un ensemble peut-être? Ou implémentez votre propre wrapper qui remplace Equals et GetHashCode.

Dictionary<KeyValuePair, bool> mySet;

for(int i = 0; i < keys.length; ++i)
{
    KeyValuePair kvp = new KeyValuePair(keys[i], values[i]);
    mySet[kvp] = true;
}

Que diriez-vous de:

Dictionary<NameValuePair,int> hs = new Dictionary<NameValuePair,int>();
foreach (i in jaggedArray)
{
    foreach (j in i)
    {
        if (!hs.ContainsKey(j))
        {
            hs.Add(j, 0);
        }
    }
}
IEnumerable<NameValuePair> unique = hs.Keys;

bien sûr, si vous utilisiez C # 3.0, .NET 3.5:

var hs = new HashSet<NameValuePair>();
hs.UnionWith(jaggedArray.SelectMany(item => item));

ferait l'affaire.

Avez-vous profilé votre code? Vous êtes certain que les boucles foreach sont le goulet d’étranglement et non pas le retriever.GetVehicles ()?

J'ai créé un petit projet test dans lequel je simule le retriever et le laisse retourner 86 000 valeurs X 11. Ma première tentative a duré 5 secondes, créant les données incluses.

J'ai utilisé la même valeur pour la clé et la valeur où la première clé était & "0 # 0 &"; et le dernier & "; 85999 n ° 10 &";

Puis je suis passé aux guids. Même résultat.

Ensuite, j'ai fait la clé plus longtemps, comme ceci:

        var s = Guid.NewGuid().ToString();
        return s + s + s + s + s + s + s+ s + s + s;

Cela a pris presque 10 secondes.

Ensuite, j'ai fait les clés incroyablement longues et j'ai eu une exception de mémoire insuffisante. Je n'ai pas de fichier d'échange sur mon ordinateur, alors j'ai immédiatement cette exception.

Combien de temps sont vos clés? Votre consommation de mémoire virtuelle est-elle la cause de vos mauvaises performances?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top