如何从 HashSet中检索实际项目?
我已阅读这个问题关于为什么不可能,但还没有找到解决问题的方法。
我想从 .NET HashSet
。我正在寻找一种具有以下签名的方法:
/// <summary>
/// Determines if this set contains an item equal to <paramref name="item"/>,
/// according to the comparison mechanism that was used when the set was created.
/// The set is not changed. If the set does contain an item equal to
/// <paramref name="item"/>, then the item from the set is returned.
/// </summary>
bool TryGetItem<T>(T item, out T foundItem);
使用这种方法在集合中搜索项目的时间复杂度为 O(1)。从 HashSet
检索项目的唯一方法是枚举所有项目,时间复杂度为 O(n)。
除了制作自己的 HashSet
或使用 Dictionary
之外,我还没有找到解决此问题的任何解决方法。还有其他想法吗?
注意:
我不想检查 HashSet
是否包含该项目。我想要获取对存储在 HashSet
中的项目的引用,因为我需要更新它(而不用另一个实例替换它)。我将传递给 TryGetItem
的项目将是相等的(根据我传递给构造函数的比较机制),但它不会是相同的引用。
I've read this question about why it is not possible, but haven't found a solution to the problem.
I would like to retrieve an item from a .NET HashSet<T>
. I'm looking for a method that would have this signature:
/// <summary>
/// Determines if this set contains an item equal to <paramref name="item"/>,
/// according to the comparison mechanism that was used when the set was created.
/// The set is not changed. If the set does contain an item equal to
/// <paramref name="item"/>, then the item from the set is returned.
/// </summary>
bool TryGetItem<T>(T item, out T foundItem);
Searching the set for an item with such a method would be O(1). The only way to retrieve an item from a HashSet<T>
is to enumerate all items which is O(n).
I haven't find any workaround to this problem other then making my own HashSet<T>
or use a Dictionary<K, V>
. Any other idea?
Note:
I don't want to check if the HashSet<T>
contains the item. I want to get the reference to the item that is stored in the HashSet<T>
because I need to update it (without replacing it by another instance). The item I would pass to the TryGetItem
would be equal (according to the comparison mechanism that I've passed to the constructor) but it would not be the same reference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
这实际上是集合中的一个巨大遗漏。您将需要一个仅包含键的字典或一个允许检索对象引用的哈希集。这么多人要求,为什么它没有得到解决,这超出了我的范围。
如果没有第三方库,最好的解决方法是使用
Dictionary
,其键与值相同,因为 Dictionary 将其条目存储为哈希表。从性能角度来看,它与 HashSet 相同,但它当然会浪费内存(每个条目的指针大小)。This is actually a huge omission in the set of collections. You would need either a Dictionary of keys only or a HashSet that allows for the retrieval of object references. So many people have asked for it, why it doesn't get fixed is beyond me.
Without third-party libraries the best workaround is to use
Dictionary<T, T>
with keys identical to values, since Dictionary stores its entries as a hash table. Performance-wise it is the same as the HashSet, but it wastes memory of course (size of a pointer per entry).您所要求的内容已被添加到一年前,并且是< a href="https://blogs.msdn.microsoft.com/dotnet/2018/04/30/announcing-the-net-framework-4-7-2/" rel="nofollow noreferrer">最近添加到 .NET 4.7.2:
签名如下(在.NET 4.7.2及以上版本中找到):
What you're asking for was added to .NET a year ago, and was recently added to .NET 4.7.2:
The signature is as follows (found in .NET 4.7.2 and above):
此方法已添加到 .NET Framework 4.7 中。 2(以及 .NET Core 2.0 之前 它);请参阅
HashSet.TryGetValue
。引用来源 :
This method has been added to .NET Framework 4.7.2 (and .NET Core 2.0 before it); see
HashSet<T>.TryGetValue
. Citing the source:重载字符串相等比较器怎么样:
然后将 HashSet 声明为:
What about overloading the string equality comparer:
And then declare the HashSet as:
现在.NET Core 2.0 有了这个确切的方法。
<一href="https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1.trygetvalue?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev 15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Collections.Generic.HashSet%601.TryGetValue);k(DevLang-csharp)%26rd%3Dtrue&view=netcore-2.0" rel="nofollow noreferrer">HashSet.TryGetValue(T, T) 方法
Now .NET Core 2.0 has this exact method.
HashSet.TryGetValue(T, T) Method
另一个技巧是通过访问 HashSet 的内部函数
InternalIndexOf
来进行反射。请记住,字段名称是硬编码的,因此如果这些字段名称在即将推出的 .NET 版本中发生更改,则会中断。注意:如果您使用 Mono,则应将字段名称从
m_slots
更改为_slots
。测试:
Another Trick would do Reflection, by accessing the internal function
InternalIndexOf
of HashSet. Keep in mind the fieldnames are hardcoded, so if those change in upcoming .NET versions this will break.Note: If you use Mono, you should change field name from
m_slots
to_slots
.Test:
在这种情况下,SortedSet 的查找时间可能是 O(log n)(如果可以选择)。仍然不是 O(1),但至少更好。
SortedSet would probably have O(log n) lookup time in that circumstance, if using that is an option. Still not O(1), but at least better.
好的,那么,你可以这样做,
这是获取所选对象的新实例。为了更新您的对象,您应该使用:
Ok, so, you can do it like this
This is to get a new Instance of the selected object. In order to update your object, then you should use:
修改了 @mp666 答案的实现,因此它可以用于任何类型的 HashSet,并允许覆盖默认的相等比较器。
Modified implementation of @mp666 answer so it can be used for any type of HashSet and allows for overriding the default equality comparer.
HashSet 有一个 Contains(T) 方法。
如果您需要自定义比较方法(例如,存储人员对象,但使用 SSN 进行相等比较),则可以指定 IEqualityComparer。
HashSet has a Contains(T) method.
You can specify an IEqualityComparer if you need a custom comparison method (e.g., store a person object, but use the SSN for equality comparison).
您还可以使用 ToList() 方法并对其应用索引器。
You can also use ToList() method and apply an indexer to that.