English 中文(简体)
将大整数列表与小整数列表比较的最有效方式是什么?
原标题:What is the Most Efficient way to compare large List of integers to smaller List of integers?

目前我有一个100万 integers list ,我对照2000年的黑名单 integer 核对每个 integer 。这大约需要2分钟。

for(int i = 0; i< MillionIntegerList.Length ; i++)
{
    for(int blacklisted = 0; blacklisted < TwoThousandIntegerList.Length ; blacklisted++)
        if(i==blacklisted)
            i = 0; //Zero is a sentinel value 
}

This makes 2,000,000,000 iterations(loops) altogether. Is there a better way Im not seeing? thanks

最佳回答

现在有三个选项 - 前两个选项比较一般, 因为它们不依赖正在排序的 < code> millionIntegerList (原未指明)。 在大列表 < em> is 已经排序的情况下, 第三种选项更可取 。

<强 > 备选1

使用LINQ(LINQ),

var common = MillionIntegerList.Intersect(TwoThousandIntegerList).ToList();

这将在内部使用 HashSet<int> 所建的 two Thousand IntegerList , 然后在其中查找 millionIntegerList 的每一个元素 - 这将比每次翻遍 two ThousandIntegerList 整个 有效得多。

如果您只想要非黑名单,您需要:

var valid = MillionIntegerList.Except(TwoThousandIntegerList).ToList();

请注意,如果您只需要一次复制结果, 您就应该删除 < code> ToList 调用 < code> to list 调用 - 我将它包括在内, 以便实现结果, 从而可以便宜地进行多次检查。 如果您只是重复使用, 除 < / code > 外, < code > 或 < code > 的返回值只会 < em> 流出结果, 从而在记忆使用方面更便宜。

<强 > 备选2

如果您不想依赖 LINQ 对对象的实施细节, 但是您仍然想要基于散列的方法 :

var hashSet = new HashSet<int>(TwoThousandIntegerList);
hashSet.IntersectWith(MillionIntegerList);
// Now use hashSet

<强 > 备选3

使用对大名单进行分类的做法肯定是有益的。

假设您不介意先对黑名单进行排序, 您可以写出类似( 未测试的)流( 和一般目的) 执行 :

// Note: to use this, you d need to make sure that *both* sequences are sorted.
// You could either sort TwoThousandIntegerList in place, or use LINQ s OrderBy
// method.

public IEnumerable<T> SortedIntersect<T>(this IEnumerable<T> first,
    IEnumerable<T> second) where T : IComparable<T>
{
    using (var firstIterator = first.GetEnumerator())
    {
        if (!firstIterator.MoveNext())
        {
            yield break;
        }

        using (var secondIterator = second.GetEnumerator())
        {
            if (!secondIterator.MoveNext())
            {
                yield break;
            }
            T firstValue = firstIterator.Current;
            T secondValue = secondIterator.Current;

            while (true)
            {
                int comparison = firstValue.CompareTo(secondValue);
                if (comparison == 0) // firstValue == secondValue
                {
                    yield return firstValue;
                }
                else if (comparison < 0) // firstValue < secondValue
                {
                    if (!firstIterator.MoveNext())
                    {
                        yield break;
                    }
                    firstValue = firstIterator.Current;
                }
                else // firstValue > secondValue
                {
                    if (!secondIterator.MoveNext())
                    {
                        yield break;
                    }
                    secondValue = secondIterator.Current;
                }  
            }                
        }
    }
}

(如果您想要使用 Icomparer<T> ,而不是以T为类比,您可以使用 Icomparer<T> 。 )

问题回答

由于大列表已经排序。 您可能会通过排序小列表( 非常快速) 取得最佳结果, 然后进行线性合并 。 您只需要查看一次大列表( 和小列表) 中的每个项目, 不需要在背景中创建 Hashbable 。

"http://en.wikipedia.org/wiki/Mege_sort">merge 函数 合并Sort的一部分,以了解如何做到这一点。

你所需要的是无数的。在我看来,除了方法(数字,数字)之外

这里请 ""http://msdn.microsoft.com/en-us/library/bb300779.aspx" rel="noreferr" >http://msdn.microsoft.com/en-us/library/bb300779.aspx

您的方法需要 O(n*n) 时间。 考虑这些优化 :

  • (1)(1)

    如果您的整数不太大, 您可以使用布布数组( 例如, 如果最大可能的整数是1000000, 请使用布 [ ] b = 新布 [ 100000] 。 现在要在黑名单中添加一个数字 K, 使用 b[ K] = true。 检查是微不足道的。 这在 O( n) 中有效 。 您也可以使用 BitAray 。

  • 2) 2)

    整数可能足够大 。 使用二进搜索树来存储黑列表( 例如 ScortedSet) 。 它有 O( logN) 插入和检索时间 。 因此, 全部是 O( N* logN) 。 语法与列表( Add( int) K, 包含( int K) ) 相同, 重复被忽略 。

I think the best solution is to use a Bloom filter and it case the Bloom filter says an element may be in the blacklist, just check if is not a false positive (which can be done in O(Log(n)) if the blacklist is sorted). This solution is time efficient and uses almost no additional space which makes it far better than using a hashset.

这是Google在Chrome黑名单中使用的解决方案。

如何在较长的列表上进行二进制搜索, 因为它已经分类了 。

foreach(integer blacklisted in TwoThousandIntegerList)
{
    integer i  = MillionIntegerList.binarySearch(blacklisted)
    if(i==blacklisted){
          //Do your stuff
    } 
}

此解决方案只花费 O( mlog n) 时间, m 是小列表的大小, n 是长列表的大小 。 < enference > Caveat: 此解决方案假设 millionIntegerList 没有重复值 。

如果情况不是这样, 那么您就可以通过重复来重复, 因为重复必须位于毗连区块中。 为此, 我将假设 < code> million InterList 是一份记录列表, 每个记录都有 < code> value 和 < code> index

foreach(integer blacklisted in TwoThousandIntegerList)
{
    integer index = MillionIntegerList.binarySearch(blacklisted)
    //Find the index of the first occurrence of blacklisted value
    while(index > 0 && MillionIntegerList[index - 1].value == blacklisted){
          --index;
    }
    while(MillionIntegerList[index].value == blacklisted){
          //Do your stuff
          ++index;
    } 
}

这个解决方案的成本 O(mlog n+mk) ,其中 k Million InterList 中每个黑名单的整数的重复平均数。

使用 HashSet 来设置被屏蔽的列表 。

foreach(integer i in MillionIntegerList)
{
        //check if blockedlist contains i
        //do what ever you like. 
}

列表使用 方法外。 这将有效





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...