繁体   English   中英

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

[英]C# Looking for a more efficient means of storing and comparing lists of true/false values

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

我还需要能够快速比较这些长度相等的列表中的任意两个列表的不相等性(即,相同值,相同顺序)。 在这种情况下,不等式是指对于一个数据集为真的时隙在另一数据集中的相同时隙中不能有任何匹配的真值。 假值无关紧要。 例如:

  • 10010和10001为“相等”,因为两个值的第一个插槽均为true
  • 00100和00001为“不相等”,因为没有一个真值落在同一位置
  • 00000和00000也“不相等”,因为它们都不具有任何真实值

比较将一遍又一遍地进行,并且需要以最快,最节省内存的方式进行。 对于给定的数据集,初始创建过程将只运行一次,因此,效率仅次于比较过程。

我尝试了按位置布尔比较来进行位置定位的布尔数组和排序列表,以及用于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;
}

我已经看过这个问题,其答案暗示了BitArrays,但是建议的答案也指出它不一定有效,我不知道这会比我已经做的更好。 我可以使用更有效的结构来加快整个过程吗?

按位与,并检查您得到的是零还是非零值。

最好,最有效的方法是使用位。 一点是计算机中较小的数据大小,也是最有效的,因为您可以使用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();
    }
}

此类只有2个方法: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();
    }

输出将如下所示:


检查存储的值:
错误,错误,正确,错误,正确,错误,正确

再次检查存储的值:
错误,错误,正确,错误,正确,错误,正确

按任意键继续...


为了比较两个集合,您只需要以所需的方式比较内部列表中的值即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM