C#寻找更有效的方法来存储和比较真/假值列表

时间:2016-10-14 17:25:55

标签: c# list boolean comparison

我有包含真/假值列表的数据集。这些列表可以是任何长度,但在大多数情况下通常在5到40个项目之间变化。在每个数据集中,所有列表的长度都相同。出于此过程的目的,列表中的元素一旦创建,将始终处于相同的顺序(即,一旦列表设置为true,false,false,true,它将始终为true,false,false,真正)。

我还需要能够快速比较这些相等长度的任何两个不等式列表(即相同顺序的相同值)。在这种情况下,通过不等式,我的意思是对于一个数据集而言为真的插槽在其他数据集的相同插槽中不能具有任何匹配的真值。虚假价值无关紧要。例如:

  • 10010和10001“相等”,因为两个值上的第一个插槽是 是的
  • 00100和00001是“不相等”,因为没有真正的值 落在同一个插槽中
  • 00000和00000也“不相等”,因为 没有任何真正的价值

比较将一遍又一遍地进行,需要以最快和最有效的方式完成。对于给定的数据集,初始创建过程只会运行一次,因此效率在比较过程中是次要的。

我已经尝试了数组和排序的布尔列表,通过位置bool比较以及执行for循环位置char值比较的字符串(“100101”格式)来执行位置。但似乎应该有更多的处理器和内存有效的方式来存储和比较这些值列表。

字符串比较版本的示例。数组和列表比较遵循相同的模式:

private bool DoListsConflict(string activeValuesA, string activeValuesB)
{
     var lengths = new int[3] {10000, activeValuesA.Length, activeValuesB.Length};

     var a = activeValuesA.ToCharArray();
     var b = activeValuesB.ToCharArray();

     for (var x = 0; x < lengths.Min(); x++)
     {
         if (a[x] == '1' && b[x] == '1') return true;
     }
     return false;
}

我看过this question,他的答案暗示BitArrays,但建议的答案也说明它并不一定有效,我不知道这会比我现在做的更好。我可以使用更有效的结构来加速整个过程吗?

2 个答案:

答案 0 :(得分:4)

按位AND并检查是否得到零或非零值。

答案 1 :(得分:0)

这样做的最佳和最有效的方法是使用位。有点是计算机中较小的数据大小,它也是最有效的,因为您可以使用ULA在不到一个机器时钟周期内操作它(当CPU管道已满时)。

为此,我在下面创建了一个名为BooleanSet的简单类。它可以使用尽可能少的内存和最少的CPU时间来存储任意数量的布尔值:

    public class BooleanSet
{
    private List<ulong> values = new List<ulong>();
    private int count = 0;
    /* 0x8000000000000000UL is the same as the binary number 1000000000000000000000000000000000000000000000000000000000000000 */
    private const ulong MsbFilterMask = 0x8000000000000000UL;
    /* 0xfffffffffffffffeUL is the same as the binary number 1111111111111111111111111111111111111111111111111111111111111110 */
    private const ulong LsbEraserMask = 0xfffffffffffffffeUL;
    public BooleanSet()
    {
        /* the set mut be initialized with a 0 value */
        values.Add(0);
    }

    /// <summary>
    /// Append a new boolean value to the list
    /// </summary>
    /// <param name="newValue">New value to append</param>
    public void Append(bool newValue)
    {
        /* Each element in list can store up to 64 boolean values.
         * If is number is going to be overcome, the set must grow up.
         */
        if (count % 64 == 63)
        {
            values.Add(0);
        }
        count++;
        /* now  we just have to shift the whole thing left, but we have
         * to preserve the MSB for lower elements:
         * 
         * We have to initialize the last MSB (Most Significant Bit) with the new value.
         */
        ulong lastMsb = newValue ? 0x1UL : 0x0UL;

        for (int position = 0; position < values.Count; position++)
        {
            /* & is the bitwhise operator AND
             * It is used as a mask to zero fill anything, except the MSB;
             * After get the MSB isolated, we just have to shift it to right edge (shift right 63 times)
             */
            ulong currentMsb = (values[position] & MsbFilterMask) >> 63;
            /* Now we have discart MSB and append a new LSB (Less Significant Bit) to the current value.
             * The | operator is the bitwise OR
             */
            values[position] = ((values[position] << 1) & LsbEraserMask) | lastMsb;
            lastMsb = currentMsb;
        }
        /* We don't have to take care of the last value, because we have did this already (3 1sf lines of this methid) */
    }

    public override string ToString()
    {
        /* Now we have to write the set as a string */
        StringBuilder sb = new StringBuilder();
        /* We have to keep track of the total item count */
        int totalCount = count;
        string separator = "";
        foreach (ulong value in this.values)
        {
            /* for each value in the internal list, we have to create a new bit mask */
            ulong bitMask = 1;
            /* We have to get all bits of all values, except the last one, because it may not be full.
             * the totalCount will let us to know where we reach the end of the list.
             */
            for (int pos = 0; pos < 64 && totalCount > 0; pos++, totalCount--)
            {
                /* We have to write the string in reverse order, because the first item is in the end of our list */
                sb.Insert(0, separator);
                sb.Insert(0, (value & bitMask) > 0);
                separator = ", ";
                bitMask = bitMask << 1;
            }
        }
        return sb.ToString();
    }
}

这个类只有两种方法:  1:Append(),用于向集合添加新值。  2:ToString(),用于按照添加的顺序列出所有存储的值。

要测试此示例,只需创建一个如下控制台应用程序:

        static void Main(string[] args)
    {
        BooleanSet set = new BooleanSet();
        set.Append(false);
        set.Append(false);
        set.Append(true);
        set.Append(false);
        set.Append(true);
        set.Append(false);
        set.Append(true);

        Console.WriteLine("Checking the stored values:");
        Console.WriteLine(set.ToString());
        Console.WriteLine();
        Console.WriteLine("Checking the stored values again:");
        Console.WriteLine(set.ToString());
        Console.WriteLine();
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

输出将如下:

  

检查存储的值:
  假,假,真,假,真,假,真

     

再次检查存储的值:
  假,假,真,假,真,假,真

     

按任意键继续......

为了比较两个集合,你只需要按照你想要的方式比较内部列表中的值。