C# 有人能给我解释一下这个GetCardinality方法在做什么吗?

C# 有人能给我解释一下这个GetCardinality方法在做什么吗?,c#,lucene.net,faceted-search,C#,Lucene.net,Faceted Search,我一直在用Lucene.NET研究分面搜索,我发现了一个很好的例子,它解释了相当多的内容,除了它完全忽略了检查位数组中项目基数的函数之外 有人能给我一个它正在做什么的概述吗?我不明白的主要事情是为什么按原样创建BitsSerray,它的用途,以及所有if语句在for循环中是如何工作的 这可能是一个很大的问题,但我必须先了解它是如何工作的,然后才能考虑在我自己的代码中使用它 谢谢 public static int GetCardinality(BitArray bitArray) {

我一直在用Lucene.NET研究分面搜索,我发现了一个很好的例子,它解释了相当多的内容,除了它完全忽略了检查位数组中项目基数的函数之外

有人能给我一个它正在做什么的概述吗?我不明白的主要事情是为什么按原样创建BitsSerray,它的用途,以及所有if语句在for循环中是如何工作的

这可能是一个很大的问题,但我必须先了解它是如何工作的,然后才能考虑在我自己的代码中使用它

谢谢

public static int GetCardinality(BitArray bitArray)
    {
        var _bitsSetArray256 = new byte[] {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
        var array = (uint[])bitArray.GetType().GetField("m_array", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(bitArray);
        int count = 0;

        for (int index = 0; index < array.Length; index ++)
            count += _bitsSetArray256[array[index] & 0xFF] + _bitsSetArray256[(array[index] >> 8) & 0xFF] + _bitsSetArray256[(array[index] >> 16) & 0xFF] + _bitsSetArray256[(array[index] >> 24) & 0xFF];

        return count;
    }
publicstaticintgetcardinality(位数组位数组)
{
var _bitsetarray256=新字节[]{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
var array=(uint[])bitArray.GetType().GetField(“m_array”,BindingFlags.NonPublic | BindingFlags.Instance).GetValue(bitArray);
整数计数=0;
for(int index=0;index>8)&0xFF]+\u位数组256[(数组[索引]>>16)&0xFF]+\u位数组256[(数组[索引]>>24)&0xFF];
返回计数;
}

使用值初始化
\u bitsetarray 256
数组,使
\u bitsetarray 256[n]
包含在
n
的二进制表示中为
0..255
中的
n
设置的位数

例如,
\u bitstarray256[13]
等于3,因为二进制中的13是
1101
,其中包含3
1
s

这样做的原因是,预先计算并存储这些值要快得多,而不是每次(或按需)都要计算出来。毕竟,13的二进制表示形式中
1
s的数量不会改变:)

for
循环中,我们在一个
uint
s数组中循环。C#
uint
是一个32位的量,即由4个字节组成。我们的查找表告诉我们一个字节中设置了多少位,因此我们必须处理这四个字节中的每一个。count+=/code>行中的位操作提取这四个字节中的每一个,然后从查找数组中获取其位计数。将所有四个字节的位计数相加,得到整个
uint
的位计数


因此,给定一个
位数组
,此函数将深入到
uint[]m_array
成员,然后返回其中
uint
的二进制表示形式中设置的总位数。

我只是想为我们这些正在使用Lucene.net开发自己版本的Faceting的人发布一篇关于位数组的有用文章。请参阅:

这是对fastet方法的一个很好的解释,可以获得整数中on位的基数(这是上面代码示例所做的大部分)

在我的分面搜索和其他一些简单的更改中实现了本文中的方法,我能够将获取计数所需的时间缩短约65%。 不同之处在于:

  • 将_bitcount声明为全局(因此它不是每次调用创建的)
  • 将for更改为foreach(ANT Profiler在此显示了25%的增长)
  • 实现65535表与256表的对比,一次移位16位,而不是8位

    private static int[] _bitcounts = InitializeBitcounts();
    
    private static int GetCardinality(BitArray bitArray)
    {
        uint[] array = (uint[])bitArray.GetType().GetField("m_array", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(bitArray);
    
        int count = 0;
        foreach (uint value in array)
        {
            count += _bitcounts[value & 65535] + _bitcounts[(value >> 16) & 65535];           
        }
        return count;
    }
    
    private static int[] InitializeBitcounts()
    {
        int[] bitcounts = new int[65536];
        int position1 = -1;
        int position2 = -1;
        //
        // Loop through all the elements and assign them.
        //
        for (int i = 1; i < 65536; i++, position1++)
        {
            //
            // Adjust the positions we read from.
            //
            if (position1 == position2)
            {
                position1 = 0;
                position2 = i;
            }
            bitcounts[i] = bitcounts[position1] + 1;
        }
        return bitcounts;
    }
    
    private static int[]_bitcounts=InitializeBitcounts();
    私有静态int GetCardinality(位数组位数组)
    {
    uint[]数组=(uint[])位数组.GetType().GetField(“m_数组”,BindingFlags.NonPublic | BindingFlags.Instance).GetValue(位数组);
    整数计数=0;
    foreach(数组中的uint值)
    {
    计数+=(u bitcounts[value&65535]+(value>>16)&65535];
    }
    返回计数;
    }
    私有静态int[]初始化EBITCounts()
    {
    int[]位计数=新的int[65536];
    int位置1=-1;
    int位置2=-1;
    //
    //循环遍历所有元素并分配它们。
    //
    对于(int i=1;i<65536;i++,位置1++)
    {
    //
    //调整我们从中读取的位置。
    //
    如果(位置1==位置2)
    {
    位置1=0;
    位置2=i;
    }
    位计数[i]=位计数[1]+1;
    }
    返回比特数;
    }
    

  • 太棒了,谢谢你,阿卡什。有些事情我仍然想不起来,但至少我理解这个方法的概念,以及它到底在做什么。