从 .NET HashSet 中按索引选择一个元素

21

目前我正在使用从HashSet派生的自定义类。在代码中有一个点,当满足某些条件时,我会选择项目:

var c = clusters.Where(x => x.Label != null && x.Label.Equals(someLabel));

代码可用并且我可以获取这些元素。但我能否接收到该集合中该元素的索引,以便在使用ElementAt方法时使用,而不是整个对象?

它应该看起来像这样:

var c = select element index in collection under certain condition;
int index = c.ElementAt(0); //get first index
clusters.ElementAt(index).RunObjectMthod();

手动迭代整个集合是更好的方法吗?需要补充说明的是,这是在一个大循环中进行的,因此这个Where子句会针对不同的someLabel字符串多次执行。

编辑

我需要这个做什么?clusters是一组某些文档集合的聚类。文档根据主题相似性分组成簇。算法的最后一步之一是为每个簇发现标签。但算法并不完美,有时会生成两个或多个具有相同标签的簇。我想做的就是将这些簇合并成一个大簇。

4个回答

32

集合一般没有索引。如果位置对你很重要,你应该使用 List<T> 来代替(或可能与之并用)集合。

现在,在 .NET 4 中,SortedSet<T> 稍有不同,它维护一个排序值顺序。然而,它仍然没有实现 IList<T>,所以使用 ElementAt 按索引访问会很慢。

如果你能详细说明为什么需要这个功能,会更有帮助。目前你的用例不是很清晰。


1
你说“如果位置对你很重要,你应该使用List<T>”,但是如果我想在我的集合中拥有唯一的条目和顺序呢? - whiteshooz
1
@whiteshooz:那就同时保留一个HashSet<T>和一个List<T>,并让它们保持同步。我不相信在BCL中有任何集合实现可以保证维护位置。 - Jon Skeet
在需要同时按数字索引和项目本身进行索引的情况下,典型的解决方案是使用Dictionary<T, int>和List<T>,并保持它们同步。 - RenniePet
@dylanh724:听起来你需要自己的集合,它由列表和集合组成。编写一个这样的集合很容易,但我不认为框架中有任何支持它的东西。 - Jon Skeet
如果您感兴趣的话,我想到了一个优雅的解决方案,可以发布为答案(现在正在使用手机)。我创建了一个扩展方法,名为AddUnique,用于List,它会检查是否包含并返回布尔值。 - dylanh724
显示剩余7条评论

10

如果您在HashSet中保存元素,并且有时需要按索引获取元素,请考虑在这种情况下使用扩展方法ToList()。 这样,您可以利用HashSet的功能,然后利用索引。

HashSet<T> hashset = new HashSet<T>();

//the special situation where we need index way of getting elements
List<T> list = hashset.ToList();

//doing our special job, for example mapping the elements to EF entities collection (that was my case)

//we can still operate on hashset for example when we still want to keep uniqueness through the elements 

1
这个安全吗?我认为当你向HashSet添加元素时,这些项可能会被重新排序,并且对ToList()的后续调用可能不总是产生相同的顺序。这只是一个猜测,我还没有看过代码,MSDN也没有透露太多信息。 - uriDium
1
@uriDium 定义“安全”。重点不在于后续调用保持相同的顺序,而仅在于使用一些对象执行函数。 - Wolfzoon
1
在进行这项工作时,请注意性能,虽然它可以正常工作。ToList() 是 O(N) 操作。 - Hardik

3

哈希集合中不存在索引。哈希集合在某些情况下获得效率的方式之一是不必维护它们。

我也看不出这里的优势在哪里。如果您要获取索引,然后使用它,这比仅获取元素要低效(获取索引同样有效,然后您还有额外的操作)。

如果您想对同一对象执行多个操作,请保留该对象。

如果您想对多个对象执行某些操作,请基于迭代它们(普通的foreach或在Where()结果上执行foreach等)。如果您想对几个对象执行某些操作,然后再对这些几个相同的对象执行其他操作,并且您必须按批次执行,则将Where()的结果存储在List<T>中,而不是在同一个foreach中执行所有操作。


0
为什么不使用字典?
        Dictionary<string, int> dic = new Dictionary<string, int>();

        for (int i = 0; i < 10; i++)
        {
            dic.Add("value " + i, dic.Count + 1);
        }

        string find = "value 3";

        int position = dic[find];

        Console.WriteLine("the position of " + find + " is " + position);

示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接