从 HashSet 中获取原始值
Get original value from HashSet
更新:
从 .Net 4.7.2 开始,HashSet.TryGetValue - docs 可用。
HashSet.TryGetValue - SO post
我对 HashSet
有疑问,因为它没有提供任何类似于 Dictionary
已知的 TryGetValue
的方法。我需要这样的方法——传递元素以在集合中查找,并从其集合中设置返回元素(找到时)。
旁注 -- "why do you need element from the set, you already have that element?"。不,我不知道,平等和身份是两个不同的东西。
HashSet
不是密封的,但它的所有字段都是私有的,因此从中派生是没有意义的。我不能改用 Dictionary
因为我需要 SetEquals
方法。我正在考虑获取 HashSet
的源代码并添加所需的方法,但许可证并不是真正的开源(我可以看,但我不能 distribute/modify)。我可以使用反射,但 HashSet
中的数组不是 readonly
,这意味着我不能在每个实例生命周期中绑定到这些字段一次。
而且我不想只为单个 class 使用完整的库。
到目前为止,我一直在使用 LINQ SingleOrDefault
。所以问题是如何解决这个问题——让 HashSet
和 TryGetValue
?
我同意这是基本上缺失的东西。虽然它仅在极少数情况下有用,但我认为它们是非常罕见的情况 - 最值得注意的是密钥规范化。
暂时只能想到一个建议,实在是犯规。
您可以在创建 HashSet<T>
时指定您自己的 IEqualityComparer<T>
- 因此创建一个记住它执行的最后一个正(即返回真值)Equals
比较的参数.然后您可以调用 Contains
,并查看要求比较器比较的内容。
注意事项:
- 这会不必要地保留引用,因此最终可能会阻止对象被垃圾回收
- 您可能希望在每个线程的基础上执行此操作(如果您有一个集合在初始化后未 修改 ,但随后 通过多线程读取,例如)
- 假设
HashSet<T>
不使用任何优化,例如 "if the references are equal, don't bother consulting the equality comparer"
- 从根本上说这是一种可怕的滥用
我一直在尝试寻找交叉点方面的其他替代方案,但我还没有找到任何地方...
如评论中所述,值得尽可能封装它 - 我怀疑您只需要一组非常有限的操作,所以我将 HashSet<T>
包装在您自己的 class 并且只公开你真正需要的操作——这样你就可以在每次操作后清除 "cache",消除我上面的第一个反对意见。
对我来说这仍然是一种可怕的虐待,但是...
正如其他人所建议的,另一种方法是使用 Dictionary<TKey, TValue>
并自己实施 SetEquals
。这很容易做到——同样,您希望将其封装在您自己的类型中。无论哪种方式,您应该首先设计类型本身,然后 然后 使用 HashSet<>
或 Dictionary<,>
作为实现细节来实现它。
听起来你用错了工具。的确,您可以使用 HashSet 节省一些内存,但在我看来,您正在尝试实现一个不同的目标:获取刚好等于表示的实际元素。
所以实际上它们是两个不同的元素。只是 memento(唯一表示)是相等的。
因此,您最好使用字典,将元素添加为 Key and Value.所以你可以找回它(相同的)但是你错过了你的 SetEquals
..
我想 SetEquals
在它的实现中与按桶顺序比较两个 HashSet 并在第一个不相等时失败没有什么不同。
因此,使用简单的 SequenceEqual()
(LINQ) 比较两个 Keys
集合也同样有效。
所以这个扩展方法可以做到
public static SetEqual<T,G>(this IDictionary<T,G> d, IDictionary<T,G> e)
{
return d.Keys.SequenceEqual(e.Keys);
}
这应该可行,因为 Dictionary
基本上是一个具有关联值的 HashSet。更适合你的问题。 (好吧,为了正确起见,代码应该使用 Dictionary<>
而不是 IDictionary<>
因为键顺序很重要)
如果第二个参数需要 IEnumerable<>
,请尝试排序以获得定义的顺序(效率不高)。
也许你应该从 HashSet
切换到 SortedSet
对于SortedSet
有一个简单的TryGetValue()
:
public bool TryGetValue(ref T element)
{
var foundSet = sortedSet.GetViewBetween(element, element);
if(foundSet.Count == 1)
{
element = foundSet.First();
return true;
}
return false;
}
调用时,该元素只需要设置比较器中使用的所有属性。它 returns 在集合中找到的元素。
希望不是瞎子,但我在任何地方都没有看到这个答案。如果你想要字典的TryGetValue
,你可以偷它。
theHashset.ToDictionary(item => item.ID).TryGetValue(key, out value)
您只需要一个用于确定唯一键的快速 lambda。
最终在 .NET 4.7.2 中添加:
HashSet.TryGetValue(T, T) Method
An SO post with more details
更新:
从 .Net 4.7.2 开始,HashSet.TryGetValue - docs 可用。
HashSet.TryGetValue - SO post
我对 HashSet
有疑问,因为它没有提供任何类似于 Dictionary
已知的 TryGetValue
的方法。我需要这样的方法——传递元素以在集合中查找,并从其集合中设置返回元素(找到时)。
旁注 -- "why do you need element from the set, you already have that element?"。不,我不知道,平等和身份是两个不同的东西。
HashSet
不是密封的,但它的所有字段都是私有的,因此从中派生是没有意义的。我不能改用 Dictionary
因为我需要 SetEquals
方法。我正在考虑获取 HashSet
的源代码并添加所需的方法,但许可证并不是真正的开源(我可以看,但我不能 distribute/modify)。我可以使用反射,但 HashSet
中的数组不是 readonly
,这意味着我不能在每个实例生命周期中绑定到这些字段一次。
而且我不想只为单个 class 使用完整的库。
到目前为止,我一直在使用 LINQ SingleOrDefault
。所以问题是如何解决这个问题——让 HashSet
和 TryGetValue
?
我同意这是基本上缺失的东西。虽然它仅在极少数情况下有用,但我认为它们是非常罕见的情况 - 最值得注意的是密钥规范化。
暂时只能想到一个建议,实在是犯规。
您可以在创建 HashSet<T>
时指定您自己的 IEqualityComparer<T>
- 因此创建一个记住它执行的最后一个正(即返回真值)Equals
比较的参数.然后您可以调用 Contains
,并查看要求比较器比较的内容。
注意事项:
- 这会不必要地保留引用,因此最终可能会阻止对象被垃圾回收
- 您可能希望在每个线程的基础上执行此操作(如果您有一个集合在初始化后未 修改 ,但随后 通过多线程读取,例如)
- 假设
HashSet<T>
不使用任何优化,例如 "if the references are equal, don't bother consulting the equality comparer" - 从根本上说这是一种可怕的滥用
我一直在尝试寻找交叉点方面的其他替代方案,但我还没有找到任何地方...
如评论中所述,值得尽可能封装它 - 我怀疑您只需要一组非常有限的操作,所以我将 HashSet<T>
包装在您自己的 class 并且只公开你真正需要的操作——这样你就可以在每次操作后清除 "cache",消除我上面的第一个反对意见。
对我来说这仍然是一种可怕的虐待,但是...
正如其他人所建议的,另一种方法是使用 Dictionary<TKey, TValue>
并自己实施 SetEquals
。这很容易做到——同样,您希望将其封装在您自己的类型中。无论哪种方式,您应该首先设计类型本身,然后 然后 使用 HashSet<>
或 Dictionary<,>
作为实现细节来实现它。
听起来你用错了工具。的确,您可以使用 HashSet 节省一些内存,但在我看来,您正在尝试实现一个不同的目标:获取刚好等于表示的实际元素。 所以实际上它们是两个不同的元素。只是 memento(唯一表示)是相等的。
因此,您最好使用字典,将元素添加为 Key and Value.所以你可以找回它(相同的)但是你错过了你的 SetEquals
..
我想 SetEquals
在它的实现中与按桶顺序比较两个 HashSet 并在第一个不相等时失败没有什么不同。
因此,使用简单的 SequenceEqual()
(LINQ) 比较两个 Keys
集合也同样有效。
所以这个扩展方法可以做到
public static SetEqual<T,G>(this IDictionary<T,G> d, IDictionary<T,G> e)
{
return d.Keys.SequenceEqual(e.Keys);
}
这应该可行,因为 Dictionary
基本上是一个具有关联值的 HashSet。更适合你的问题。 (好吧,为了正确起见,代码应该使用 Dictionary<>
而不是 IDictionary<>
因为键顺序很重要)
如果第二个参数需要 IEnumerable<>
,请尝试排序以获得定义的顺序(效率不高)。
也许你应该从 HashSet
切换到 SortedSet
对于SortedSet
有一个简单的TryGetValue()
:
public bool TryGetValue(ref T element)
{
var foundSet = sortedSet.GetViewBetween(element, element);
if(foundSet.Count == 1)
{
element = foundSet.First();
return true;
}
return false;
}
调用时,该元素只需要设置比较器中使用的所有属性。它 returns 在集合中找到的元素。
希望不是瞎子,但我在任何地方都没有看到这个答案。如果你想要字典的TryGetValue
,你可以偷它。
theHashset.ToDictionary(item => item.ID).TryGetValue(key, out value)
您只需要一个用于确定唯一键的快速 lambda。
最终在 .NET 4.7.2 中添加:
HashSet.TryGetValue(T, T) Method
An SO post with more details