关于c#:从HashSet获取原始值

您所在的位置:网站首页 怎么把hashset中的值存入数组 关于c#:从HashSet获取原始值

关于c#:从HashSet获取原始值

2024-07-13 05:06| 来源: 网络整理| 查看: 265

更新: 从.Net 4.7.2开始,可以使用HashSet.TryGetValue-docs。 HashSet.TryGetValue-SO帖子

我对HashSet有问题,因为它没有提供与Dictionary已知的TryGetValue类似的任何方法。我需要这样的方法-传递元素以在集合中找到,并从其集合中设置返回元素(如果找到)。

旁注-"为什么需要集合中的元素,而您已经具有该元素?"。不,我不是,平等和认同是两回事。

HashSet不是密封的,但是其所有字段都是私有的,因此从中派生是没有意义的。我不能使用Dictionary,因为我需要SetEquals方法。我当时在考虑获取HashSet的源并添加所需的方法,但是该许可证并不是真正的开源(我可以看,但不能分发/修改)。我可以使用反射,但是HashSet中的数组不是readonly,这意味着每个实例生存期一次都无法绑定到那些字段。

而且我不想仅对单个类使用完整的库。

到目前为止,我仍然坚持使用LINQ SingleOrDefault。所以问题是如何解决-将HashSet与TryGetValue一起使用?

相关讨论 提供一个哈希集中的内容以及TryGetValue的工作方式的代码示例可能会有所帮助! 无论是否在集合中找到该项目,以及是否找到集合中存在的项目,TryGetValue都将返回true / false。 在HashSet私有成员周围定义自己的ISet门面。 为什么要在身份重要的键上使用哈希集?您是在编码自己的实习机制还是类似的东西?您是否正在使用SetEquals与另一个集合或另一个集合进行比较? @卢安,身份本身并不重要,我指出,平等不是身份。换句话说,我发现的事实与手头的事实相同,并不意味着这些元素是相同的。我需要SetEquals来检查两组是否相等。 @greenoldman我明白这一点。我问的是身份对您很重要的部分-为什么您需要从哈希集中读取值,而不是使用已有的哈希值? @Luaan,因为每个元素不仅包含用于检查相等性的数据,而且还包含不用于此检查且用于其他目的的数据,因此我不能丢失它们,也不能仅因为两项相等而交换它们。

可能您应该从HashSet切换到SortedSet

SortedSet有一个简单的TryGetValue():

12345678910public bool TryGetValue(ref T element) {     var foundSet = sortedSet.GetViewBetween(element, element);     if(foundSet.Count == 1)     {         element = foundSet.First();         return true;     }     return false;       }

调用时,该元素仅需要比较器中使用的所有属性集。它返回在Set中找到的元素。

相关讨论 谢谢,很高兴在我的"工具箱"中也有这种方法:-)。

我同意这基本上是缺少的东西。尽管它仅在极少数情况下有用,但我认为它们是非常罕见的情况-最值得注意的是关键规范化。

我现在只能想到一个建议,这确实是犯规的。

您可以在创建HashSet时指定自己的IEqualityComparer-因此,请创建一个记住其执行的最后一个正(即真返回)Equals比较的参数的参数。然后,您可以调用Contains,并查看要求相等比较器进行比较的内容。

注意事项:

这会不必要地保留引用,因此最终可能会阻止对象被垃圾回收 您可能希望在每个线程的基础上执行此操作(例如,如果您有一个在初始化后未修改但会被多个线程读取的集合) 它假定HashSet不使用任何优化方法,例如"如果引用相等,则不必费心咨询相等性比较器" 从根本上讲这是一种可怕的虐待

我一直在尝试寻找交叉路口的其他选择,但我还没有任何地方...

如评论中所述,最好将其尽可能地封装-我怀疑您只需要一组非常有限的操作,因此我将HashSet包装在您自己的类中,并且只公开了您真正需要的操作-这样,您就可以在每次操作后清除"缓存",从而消除了我上面的第一个反对意见。

对我来说,这仍然是一种可怕的虐待,但是...

正如其他人所建议的那样,替代方法是使用Dictionary并自己实现SetEquals。这样做很简单-再次,您需要将此封装为您自己的类型。无论哪种方式,您都应该首先设计类型本身,然后使用HashSet或Dictionary作为实现细节来实现它。

相关讨论 谢谢!!!幸运的是,我不需要将其公开给其他人,而且我有单线程应用程序(到目前为止)。第三点很容易解决-如果存在匹配,并且未触发比较器,则意味着找到了传递给方法的元素。我将让我的问题开放一段时间,希望您不要介意。 如果走这条路线,我会考虑将其封装在新的hashset-type类中,以便您公开有意义的方法。这将使将来更容易发现您当前的假设也施加了限制,例如不是线程安全的。您也可以通过始终要求比较器在使用后清除其缓存来缓解"不必要地保留对引用的引用"问题。换句话说,不要在各处散布Ask-Hashset-Check-Comperer代码,将其封装在视线之外。 @ LasseV.Karlsen:很好,是的。我仍然不确定我是否真的会建议使用此方法,但是至少封装它是一个好的开始。将编辑我的答案。 @greenoldman:可以肯定地保持问题开放-并查看我的编辑和Lasses评论以进行改进。它仍然是一个非常丑陋的hack :( @WouterHuysentruit:嗯,OP专门说"我不能使用Dictionary,因为我需要SetEquals方法。"但是他们当然可以自己重新实现。 如果内存和CPU性能至关重要,那么这是一个不错的解决方案。否则请远离它。虽然公平地说,HashSet也不是线程安全的,并且如果将其封装为自己的类型以隐藏滥用,那是安全的。只是别忘了还要修复所有对于HashSet参数具有不同行为的方法,否则您将始终失去性能。继承和组合相结合总是很痛苦:/ 俗话说"线性杀了猫" :-)太可怕了,不可怕,我实现了这个想法,并设法从7:30刮掉了1:20分钟(如果您问我的话,还不错-当然,我事先知道通过集合进行线性搜索是瓶颈)。因此,再次感谢您!

最终在.NET 4.7.2中添加:

HashSet.TryGetValue(T,T)方法

带有更多详细信息的SO帖子

听起来您尝试使用错误的工具。没错,您可以使用HashSet节省一些内存,但是在我看来,您正在尝试实现一个不同的目标:获取与表示形式相等的实际元素。 因此,实际上它们是两个不同的元素。只是纪念品(独特的表示)是相等的。

因此,最好使用在字典中添加元素作为键和值的字典。因此,您可以将其取回(相同),但是您错过了SetEquals...。

我想在它的实现中,SetEquals与按存储桶顺序依次比较两个HashSet并没有什么不同,并且在第一个不相等时失败。

因此,您应该使用简单的SequenceEqual()(LINQ)比较两个Keys集合,也应该会感到满意。

所以这种扩展方法可以做到

1234public static SetEqual(this IDictionary d, IDictionary e) {     return d.Keys.SequenceEqual(e.Keys); }

这应该起作用,因为Dictionary基本上是具有关联值的HashSet。而且更适合您的问题。 (好的,正确的是,代码应该用于Dictionary而不是IDictionary,因为密钥顺序很重要)

如果在第二个参数上需要IEnumerable,请尝试排序以获取定义的顺序(效率不高)。

相关讨论 当您将一个集合与另一个集合进行比较时,实现方式有所不同-在这种情况下,它可以使用更直接,更高效的比较。否则,SequenceEqual或多或少是等效的。 Wont SequenceEqual是否也施加排序?包含相同数量元素且具有相同容量的两个字典可能具有相同的键顺序,但是如果它们具有不同的容量,则肯定不是这样。字典键的顺序是未记录的行为。 您只是在将一个问题换成另一个,最后我还是有问题。如何在Dictionary键上有效地实现SetEquals(或值无关紧要,因为在这种情况下它将是一对双胞胎)。 如前所述,不能保证或记录一组键或元素的顺序。没错,能力会影响它(对此有所考虑)。因此,为了安全起见,唯一有效的检查将是ORDER + SequenceEquals。按哈希值排序可能是一个提示,但没有它是不可能的。我敢打赌,即使您实现自己的HashSet,验证Set-Identity也是同样的问题。由于N x N个相等的组合。因此CS具有引入命令然后检查的解决方案。 => O(N) 根据您的最后一条评论,最好编辑您的答案,以表明需要对两组键施加某种排序顺序:不正确,不能直接比较两个键序列。

希望不是盲人,但我在任何地方都没有看到这个答案。如果您想要字典的TryGetValue,则可以窃取它。

1theHashset.ToDictionary(item => item.ID).TryGetValue(key, out value)

您所需要做的就是快速确定唯一密钥的lambda。

相关讨论 这整个主题充满了Dictionary-Ctrl + F是您的朋友。 明显。我是否说我没有看到任何人使用Dictionary?不,我说我没有看到这个^^^答案。 CS人群,一如既往的傲慢自大。一定要爱。 也许您没有看到这个特定答案,因为它是不正确的? Dictionary没有SetEquals,我在问题中写了它。 不正确怎么办?哈希集和字典很容易互换。只需将结果转换回哈希集并使用哈希集setequals ... "仅转换"意味着额外的内存分配。 和?据我所知,它仍然是正确的解决方案。也许不是最有效的,但是它干净整洁,我怀疑您所做的任何事情都将使效率更高。只是挑剔地掩盖自己。 您能否提出任何答案可以替代OP已经说过的"后备"解决方案LINQs SingleOrDefault的有用情况?编辑:我只是想到一个:如果一个人要进行大量的TryGetValue测试,在不更改集合的时间,那么创建此字典可能是有意义的,因为创建它的成本将被摊销在所有这些用途上。 @greenoldman-恕我直言,其他答案使用字典的方式大不相同。在这里,建议是临时创建字典以执行TryGetValue。因此,该字典不需要SetEquals。这可能是有用的建议,也可能不是有用的建议(我怀疑任何人都会这样做),但这确实是一个新建议。 [一种相关方法是同时维护HashSet和字典。] @ToolmakerSteve,为什么要编辑答案而不是评论(带有添加的内容)?注释正是为此目的而做出的。或者直接回答问题。您不会被批评,询问,编辑有其他目的-修正错别字,弄清楚问题等。 @greenoldman-我在上面的评论中对您的问题感到困惑。我没有编辑此答案。您是指我对原始问题的编辑吗?尽管我同意这是不寻常的动作,但在这种情况下,至关重要的是,任何访问此页面的人都必须知道.NET已更新,因此他们可能不必为这些旧方法而苦恼。对未来读者的利益是SO的主要目的。我们达成目标了吗?我是否误解了您的担忧? @ToolmakerSteve,对不起,我的意思是"问题"。当然,它可以保持这种状态,但是由于它是就地编辑,因此无法对其进行注释。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3