【问题标题】:Collection for fast read in C#在 C# 中快速阅读的集合
【发布时间】:2013-02-07 23:14:05
【问题描述】:

我正在为以下场景寻找一个集合类:

  • 快速集合查找,一次一项。
  • 该集合包含大约 300 K 项。
  • 收集填充速度可能并不重要,但理想情况下也很快。
  • 加载集合后无需更新/删除/插入

将填充到集合中的 Ip2Location 类型的项目示例:

public class Ip2Location
{
   public long IpFrom {get; set;}
   public long IpTo {get; set;}
   public string Country {get; set;}  
}

IpFrom      IpTo        Country
16909056    16909311    AU
16909312    16941055    US

通过指定的 IP 对集合进行项目查找,如下所示:

IpFrom < currentIp < IpTo

任何想法,包括参考链接,将不胜感激!

比较:HashSet, SortedSet

有没有更好的集合类?

参考:下面链接中的对照表: http://geekswithblogs.net/BlackRabbitCoder/archive/2011/06/16/c.net-fundamentals-choosing-the-right-collection-class.aspx

更新

使用 Array.BinarySearch 的问题:

var index = Array.BinarySearch(ipCountries, new IpCountry { IpFrom = 16909056}, new Ip2LocationComparer());

它适用于少量行,不适用于 300k 项(例如索引为 -(totalrow+1) )。搜索项加载在 300 K 项集合中。

        public class Ip2LocationComparer: IComparer<IpCountry>
        {
            public int Compare(IpCountry x, IpCountry y)
            {
                if (x != null && y != null)
                    return (x.IpFrom <= y.IpFrom && y.IpFrom <= x.IpTo)? 0 : -1;

                return -1;

            }
        }

更新 2

我改成下面了

public class Ip2LocationComparer: IComparer<IpCountry>
            {
                public int Compare(IpCountry x, IpCountry y)
                {
       if (x != null && y != null)

            {
                if (x.IpFrom > y.IpFrom)
                    return 1;

                if (x.IpFrom < y.IpFrom)
                    return -1;

                if (x.IpFrom == y.IpFrom)
                {
                    if (y.IpFrom > x.IpTo)
                        return 1;

                    if (y.IpFrom < x.IpTo)
                        return -1;

                }

            }

            return 0;
}

但是 BinarySearch 的索引返回仍然是 nagtive,正好在匹配项和后续项之间。例如如果我的搜索 IpFrom 是 3,则索引在 2 和 4 之间。为什么它不返回 2?我还没有测试 IpTo 场景。

任何想法将不胜感激!

【问题讨论】:

  • 您的搜索方法不起作用,因为您的比较器...损坏了。如果 x 在 y 之前,则需要返回 -1,如果 x 和 y 相同,则需要返回 0,如果 y 在 x 之后,则需要返回 1。在您的情况下,如果结果为零(也带有空检查),您几乎肯定希望实现是 x.IpFrom.CompareTo(y.IpFrom) and then return the IpTo` 比较。这将为您提供范围内的第一个项目。然后继续前进,直到找到to 范围在当前项目之前的项目,然后你就完成了。
  • 感谢您的评论。我发布了更新 2。请看一下,任何想法都会非常感激!
  • 您的比较器现在可以正常工作了。你可以用更少的代码做到这一点,但你所拥有的并没有错。 BinarySearch 旨在返回负值;只需查看该方法的文档和 MSDN 上的示例即可了解其正确用法。
  • 谢谢! Update 1 中的比较器适用于行数较少的测试用例,但不适用于 30 万个项目。有什么想法吗?
  • 第一个比较器完全坏了。如果它成功了,那纯属运气,因为套装太小了。

标签: c#


【解决方案1】:

您可以将其存储在数组中。

如果您在填充后对数组进行排序,那么BinarySearch 将是一种非常快速的查找currentIp 所在位置的方法。

【讨论】:

  • 谢谢! HashSet 和 SortedSet 呢?你的意思是按 IpFrom 排序?因为 IpFrom 是独一无二的。
  • 不,您需要一个数组和二进制搜索来查找您正在做的事情。哈希集或排序列表必须进行查找,即使您可以遍历它们,它们也不可能像二分搜索那样高效。
  • @Pingpong 一个按 IpFrom 排序的普通数组将适用于 IpFrom 上的二进制搜索
  • 谢谢!我会测试它,并发布结果。
  • 我在使用 BinarySearch 获取查找项时遇到问题。我在更新部分发布了我的发现。你能看看吗?
【解决方案2】:

数据结构方面,您可以尝试使用字典或排序列表,尽管有 300000 个项目,您可能会遇到问题。不过,我很想知道结果。带有 BinarySearch 的普通数组也可能不是一个坏选择。

您还可以考虑利用机器上的所有内核进行快速查找。您可以在大多数集合上使用.AsParallel() extension method,这将使集合准备好在多个内核上进行查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    相关资源
    最近更新 更多