Pourquoi ne puis-je récupérer un élément à partir d'un HashSet sans énumération?
Je suis à la recherche pour un aperçu de la têtes de HashSet concepteurs. Pour autant que je suis au courant, ma question s'applique à la fois à Java et C# HashSets, me faisant penser il doit y avoir une bonne raison pour cela, mais je ne peux pas penser à tout moi-même.
Après j'ai inséré un article dans un HashSet, pourquoi est-il impossible de récupérer cet élément sans énumération, à peine un fonctionnement efficace? Surtout depuis qu'un HashSet est explicitement construit d'une manière qui contribue à l'efficacité de la récupération.
Il serait souvent utile pour moi d'avoir Supprimer(x) et Contient(x) de retour de l'élément réel est en cours de suppression ou de contenus. Ce n'est pas nécessairement l'élément je passe à la Supprimer(x) ou Contient(x) de la fonction. Bien sûr, je suppose que je pourrais obtenir le même effet par le biais d'une table de hachage, mais pourquoi perdre tout ce que l'espace et de l'effort quand il doit être parfaitement possible de le faire avec un set?
Je peux comprendre qu'il peut y avoir certains problèmes de conception que l'ajout de cette fonctionnalité permet les utilisations de HashSet qui ne sont pas compatible avec leur rôle ou un rôle à l'avenir dans le cadre, mais si c'est le cas, quels sont ces problèmes de conception?
Modifier
De répondre à quelques questions, voici plus de détails:
Je suis en utilisant un immuable type de référence avec substituée hashcode, d'égal à égal, etc pour émuler un type de valeur dans C#. Disons que le type a des membres A, B, et C. Hashcode, d'égal à égal, etc dépendre uniquement de A et B. compte tenu de certains A et B je veux être en mesure de récupérer l'équivalent de l'élément à partir d'un hashset et c'est faire le C. je ne vais pas être en mesure d'utiliser HashSet pour cela, il s'affiche, mais je voudrais au moins savoir si il n'y a aucune bonne raison pour cela. Le Pseudo-code suivant:
public sealed class X{
object A;
object B;
object extra;
public int HashCode(){
return A.hashCode() + B.hashCode();
}
public bool Equals(X obj){
return obj.A == A && obj.B == B;
}
}
hashset.insert(new X(1,2, extra1));
hashset.contains(new X(1,2)); //returns true, but I can't retrieve extra
- "pourquoi est-il impossible de récupérer cet élément sans énumération" Pourriez-vous préciser ce que vous entendez ici, entendez-vous get(), contient() est O(n) dans votre cas?
- Sûr 🙂 je voulais dire que je ne peut pas récupérer la référence exacte je l'ai mis dans le jeu sans que l'énumération. Il n'y a pas de get() de l'opérateur pour HashSet, et contient() prend un argument qui est sans doute évalue à égal à la référence que vous mettez, mais peut-être pas la référence exacte que vous mettez dans. J'espère que efface jusqu'à.
- Dans ce cas, vous pouvez mettre en œuvre votre equals() de retour cette == obj - I. e. pour vérifier que la même référence. Sans la création d'un objet de contrôle, c'est un prix élevé à payer. Et la création d'un objet de contrôle serait peut résoudre le problème seul.
- Il vous manque que le hachage n'est pas nécessairement unique. Il est juste et outil d'indexation.
- C'est ajouté .NET au moins (v4.7.2).
Vous devez vous connecter pour publier un commentaire.
Comment avez-vous été en proposant de récupérer l'élément de la table de hachage ensemble? Un ensemble est, par définition, n'est pas ordonné de quelque manière et par conséquent, il n'y a pas d'indice à utiliser pour récupérer l'objet en question.
Définit, en tant que concept, sont utilisés pour tester l'inclusion, c'est à dire si oui ou non l'élément en question est dans la table de hachage de l'ensemble de données. Si vous êtes à la recherche pour récupérer une valeur à partir d'une source de données à l'aide d'une clé de valeur ou d'un indice, je suggère de regarder dans un Carte ou un Liste.
EDIT: réponse Supplémentaire basée sur la modification de la question d'origine
Soonil, basé sur les nouvelles informations, il semble que vous pourriez être intéressé à la mise en œuvre de vos données en Java Enum, quelque chose de semblable à ceci:
Enum héritent automatiquement des valeurs de() qui retourne la liste de toutes les valeurs de l'enum est "ensemble", que vous pouvez utiliser pour tester l'inclusion à l'encontre de la même manière que l'Ensemble. Aussi, parce que c'est un complet de la classe, vous pouvez définir de nouvelles méthodes statiques pour faire le composite logique (comme j'ai essayé de faire allusion à l'exemple de code). La seule chose à propos de l'Enum est que vous ne pouvez pas ajouter de nouvelles instances au moment de l'exécution, qui peut ne pas être ce que vous voulez (bien que si l'ensemble de données de taille ne va pas croître au moment de l'exécution, l'Enum est ce que vous voulez).
HashSet
inclus), puis les méthodes d'extensionFirst()
et/ouSingle()
sont exactement ce que vous voulez ou avez besoin.SoonilsDataType
. Surtout depuis la publication du code échoue,getCompositeValue
ne dispose pas d'une instruction de retour à l'extérieur de l'instruction if.hashset-without-enumeration
partie, probablement, je n'ai pas remarqué ce andresp!=sooniln, merci! 🙂Dans .Net, ce que vous êtes probablement à la recherche pour est KeyedCollection
http://msdn.microsoft.com/en-us/library/ms132438.aspx
Vous pouvez obtenir autour de la méchanceté de re-mise en œuvre de cette classe abstraite chaque fois avec un certain "générique" de l'intelligence. (Voir IKeyedObject`1.)
Remarque: Tout objet de transfert de données qui implémente IKeyedObject`1 doit avoir un substituée méthode GetHashCode simplement de retourner ce.Clé.GetHashCode(); et de même pour les est égal...
Ma Bibliothèque de classes de Base se termine généralement avec quelque chose comme ça:
KeyedCollection<TItem, TItem>
devrait être utile dans le réel.Si vous modifiez un objet après qu'il a été inséré, il est de hachage ont peut-être changé (ce qui est particulièrement probable si hashCode() a été remplacée). Si les modifications de hachage, une recherche dans l'ensemble échouera, car vous serez de la tentative de rechercher un objet qui est haché à un autre endroit que c'est stockée dans.
Aussi, vous devez vous assurer que vous avez remplacé hashCode et equals dans votre objet si vous voulez la recherche de l'égalité des objets qui sont des instances différentes.
Remarque que c'est tout pour Java - je suis en supposant que C# a quelque chose de similaire, mais comme il a été plusieurs années puisque j'ai utilisé le C#, je vais laisser les autres parler à ses capacités.
J'imagine que les concepteurs de la
Set
interface etHashSet
classe voulais m'assurer que leremove(Object)
méthode définie sur laCollection
l'interface a également été applicable àSet
; cette méthode renvoie une valeur booléenne indiquant si l'objet a été supprimé avec succès. Si les concepteurs ont voulu fournir des fonctionnalités selon lequel remove(Object) a renvoyé l' "égalité" objet déjà dans leSet
cela signifierait une autre signature de la méthode.Aussi, étant donné que l'objet en cours de suppression est logiquement égale à l'objet passé en remove(Object) il est permis de penser au sujet de la valeur ajoutée dans le retour de l'objet contenu. Cependant, j'ai eu ce problème moi-même avant et ont utilisé une Carte de résoudre le problème.
Noter qu'en Java, une
HashSet
utilise unHashMap
en interne et donc il n'y a pas de stockage supplémentaire de frais généraux à l'aide d'unHashMap
à la place.Pourquoi ne pas simplement utiliser un
HashMap<X,X>
? C'est exactement ce que vous voulez. Il suffit de ne.put(x,x)
à chaque fois et puis vous pouvez juste obtenir le stockés élément égal à x avec.get(x)
.C'était un oubli de la bibliothèque de designers. Comme je l'ai mentionné dans une autre réponse, cette méthode a été ajoutée à .NET Framework 4.7.2 (et .NET Core 2.0 avant); voir
HashSet<T>.TryGetValue
. Citant la source:Me ressemble vous êtes actuellement à la recherche d'un
Map<X,Y>
, où Y est le type deextra1
.(diatribe ci-dessous)
La equals et hashCode méthodes de définir significative objet d'égalité. La classe HashSet suppose que si deux objets sont égaux en tant que définie par
Object.equals(Object)
il n'y a pas de différence entre ces deux objets.J'irais même jusqu'à dire que si le
object extra
est significatif, votre design n'est pas l'idéal.RÉSOLU. Désireux de trouver un élément qui semble parfaitement valable pour moi, parce que le représentant de recherche peuvent différer de l'élément trouvé. Cela est particulièrement vrai si les éléments contiennent de la clé et de la valeur de l'information, et une coutume comparateur d'égalité compare la clé en partie seulement. Voir l'exemple de code. Le code contient un comparateur qui met en œuvre une recherche personnalisée et qui capture l'élément trouvé. Cela nécessite une instance de la comparer. Désactivez la référence à l'élément trouvé. Effectuer une recherche par le biais de l'affiche. Accéder à l'élément trouvé. Être conscient de multithread questions lors du partage de la comparer instance.
Ensemble des objets dans ces langues ont été principalement conçu comme un ensemble de valeur, pas pour les objets mutables. Ils vérifient que l'objet mis en eux sont uniques en utilisant des égaux. C'est pourquoi les contient et les supprimer retourne un booléen, pas de l'objet: ils vérifier ou supprimer la valeur que vous leur passer.
Et en fait, si vous faites un contenant(X) sur un ensemble, et s'attendent à obtenir un objet différent de Y, cela signifie que X et Y sont égaux (c'est à dire X. equals(Y) => true), mais quelque peu différente, ce qui semble erroné.
HashMap<T>
avec une opération qui pourrait revenir le passé-élément serait l'idéal.M'a donné une intéressante suggestion sur la manière d'utiliser une Carte, en ayant mes propres objets se définissent eux-mêmes comme KeyValuePairs. Alors qu'un bon concept, malheureusement KeyValuePair n'est pas une interface (pourquoi pas?) et c'est un struct, où l'on tire que du plan de l'air. En fin de compte je vais rouler mon propre Jeu, comme mes contraintes me permettre cette option.
Réponse courte; car les éléments ne peuvent pas être garantis pour être immuable.
J'ai atteint exactement le problème que vous décrivez, où le HashCode est basée sur les champs fixes dans le membre de classe, mais la classe contient des informations supplémentaires qui peuvent être mis à jour sans changer la valeur de hachage.
Ma solution a été de mettre en œuvre un générique MyHashSet<T> sur la base de ICollection<T>, mais enveloppé d'un Dictionnaire<int, List<T>> à fournir la recherche de l'efficacité, où la clé de type int est le HashCode de T. Cependant, cela montre que si le HashCode de la membre des objets peut changer la recherche dans le dictionnaire, suivie par la comparaison d'égalité des éléments de la liste ne sera jamais trouver les éléments modifiés. Il n'y a pas de mécanisme pour forcer les membres à être immuable, donc la seule solution consiste à énumérer le lot.
Après demandais la même chose, et finement être capable de regarder le code source:
source: http://referencesource.microsoft.com/#System.Core/System/Collections/Generic/HashSet.cs
Un ensemble est une collection d'objets uniques (des objets ou des valeurs). Dans l' .net de la mise en œuvre d'un élément est le même que l'autre élément (et non unique) si la méthode Equals de la comparer retourne vrai pour les deux articles. Pas si les deux objets ont le même code de hachage. ainsi, une vérification de l'existence d'un élément est un processus en deux étapes. la première utilisation de l'hashset afin de minimiser le nombre d'éléments à compere, puis la compression elle-même.
Si vous souhaitez récupérer un élément, vous devez être en mesure de fournir la récupération de la fonction avec un identifiant unique. vous connaissez peut-être le code de hachage de l'élément que vous voulez. mais cela ne suffit pas. comme plus d'un élément peut avoir le même hash. vous aurez également besoin de fournir l'élément lui-même, de sorte que l'Égalité de méthode peut être appelée. et clairement si l'objet n'est pas une raison pour l'obtenir.
On pourrait créer une structure de données qui exige qu'aucun des deux objets uniques jamais revenir par le même code de hachage. et que vous pourriez obtenir un élément de celui-ci. il sera plus rapide de l'ajout d'*, et la récupération sera possible si vous connaissez le code de hachage. si deux éléments qui ne sont pas égales, mais de retour le même hachage sont mis dans le premier sera remplacé. pour autant que je sais que ce Type n'existe pas dans .net , et non ce n'est pas le même comme un dictionnaire.
*étant donné que la GetHash méthode est la même.