存储六个uint的最小可能方式

时间:2013-01-14 00:22:35

标签: c# bit-shift

如果我有数字1,2,3,4,5和6,并且我想以尽可能小的方式存储它们的某些组合,我该怎么做?

例如,我可能想要存储1,4和5.或者可能存储2,4,5和6.或者甚至可能存储所有六个数字。我将始终至少有一个需要存储的号码。我想我可能已经看到这有点移位完成但我不完全理解它是如何工作的。对于它的价值,我的最终目标是节省绝对最大空间量,因为这些值需要存储在具有极小存储空间的硬件设备上。

编辑----------------------------------------

感谢大家提出的所有好建议。我只是想澄清一下,我的应用程序中的实现并不一定需要尽可能小,只是我理解的东西,并且对我身后的其他开发人员有意义。最重要的是能够以尽可能小的方式表示这些值,因为我最终必须构建具有其他几个值的字节数组,并将其全部写入存储非常有限的设备。再次感谢你们的好建议!

7 个答案:

答案 0 :(得分:6)

[Flags]
public enum NumberEnum : byte
{
    None = 0,
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32
};

public string ExampleMethodWithNumberCombinationsAsAEnum(NumberEnum filterFlags = 0)
{
 if ((filterFlags & NumberEnum.One) == NumberEnum.One)
 {
    //Do something with one
 }

 if (((filterFlags & NumberEnum.One) == NumberEnum.One) && ((filterFlags & NumberEnum.Two) == NumberEnum.Two))
 {
    //Do something with one & two
 }
}

答案 1 :(得分:1)

想象你可以将它存储在bool的数组中并不是很难。现在,考虑一下,有点什么?有点可以表示两个状态,就像bool一样。现在,整数由位组成。我知道的最小的C#可用bytebyte有八位。您可以为每个必须存储的数字使用其中一个位。让我们将从最低有效位到最高有效位的位数进行编号。我们可以在位0中存储1,在位1中存在2,在位2中存储3,依此类推。现在我们有了数据的表示。

我们如何打包数据?你提到了位移,你是对的。您可能希望使用位移,但您可能还需要使用其他一些操作;特别是~(NOT),&(AND)和|(OR)。

总之,你会有这样的事情:

byte flags = 0;

// Let's add 2.
flags |= 1 << (2 - 1);

// Is 2 in it?
if(flags & (1 << (2 - 1)) != 0) {
    // Yes.
}else{
    // No.
}

// Let's remove 2.
flags &= ~(1 << (2 - 1));

这是如何工作的?如果1(位位置0中的1)表示存在1,我们可以将其左移位位位时间,以便在该位位置获得1。将两个字节组合在一起将采用集合的并集; ANDing将采取交叉点。 a & ~bb删除a中设置的所有位。

答案 2 :(得分:1)

你说你需要节省空间,但你没有提到RAM。这是一种方法,它可以占用更多的虚拟内存,但可以让你编写更简单的代码。

readonly Dictionary<int, int> _dictionary =
        Enumerable.Range(1, 6).ToDictionary(i => i, i => 1 << i - 1);

int GetFlags(params int[] ints)
{
    //Do checks on the dictionary, etc.
    return ints.Aggregate(0, (current, i) => current | _dictionary[i]);
}

然后,您可以通过以下代码使用代码:

var a = 1;
var b = 4;
var c = 5;
var result = GetFlags(a, b, c);

或者,可以通过以下方式重写GetFlags的正文:

var result = 0;
foreach (var i in ints)
    result |= _dictionary[i];
return result;

答案 3 :(得分:1)

[Flags]
public enum UIntEnum : byte
{
    None = 0x0,
    One = 0x1,
    Two = 0x2,
    Three = 0x4,
    Four = 0x8,
    Five = 0x10,
    Six = 0x20
};

public static class UIntEnumExtensions
{
    public static Boolean ContainsOne(this UIntEnum enum)
    {
        // For .NET < 4.0
        // return ((enum & UIntEnum.One) == UIntEnum.One);
        // For .NET >= 4.0
        return enum.HasFlag(UIntEnum.One);
    }

    public static Boolean ContainsTwo(this UIntEnum enum)
    {
        // For .NET < 4.0
        // return ((enum & UIntEnum.Two) == UIntEnum.Two);
        // For .NET >= 4.0
        return enum.HasFlag(UIntEnum.Two);
    }

    // And so on...

    public static List<UInt32> GetComponents(this UIntEnum enum)
    {
        List<UInt32> values = new List<UInt32>();

        if (enum.ContainsOne())
            values.Add((UInt32)1);

        if (enum.ContainsTwo())
            values.Add((UInt32)2);

        // And so on...
    }
}

然后,例如:

UIntEnum enum = UIntEnum.Two | UIntEnum.Six;

if (enum.ContainsSix())
    Console.WriteLine("Enum contains Six!");

foreach (UInt32 value in enum.GetComponents())
    Console.WriteLine("Enum contains " + value.ToString() + "!");

答案 4 :(得分:1)

您可以使用一个字节的六位来存储组合,这意味着您可以在每个字节中存储一个组合的三分之一,或者三个字节中的四个组合:

+--------+--------+--------+
|12345612|34561234|56123456|
+--------+--------+--------+

要将值数组转换为6位值:

public static int GetCombination(int[] combination) {
  int n = 0;
  foreach (int a in combination) {
    switch (a) {
      case 1: n |= 1;
      case 2: n |= 2;
      case 3: n |= 4;
      case 4: n |= 8;
      case 5: n |= 16;
      case 6: n |= 32;
    }
  }
  return n;
}

将这些值中的四个组合成三个字节:

public static byte[] PackCombinations(int[] values) {
  byte[] result = new byte[3];
  result[0] = (byte)((values[0] << 2) | (values[1] >> 4));
  result[1] = (byte)((values[1] << 4) | (values[2] >> 2));
  result[2] = (byte)((values[2] << 6) | (values[3]));
  return result;
}

答案 5 :(得分:0)

如果 C#可以处理C ++ STL的内容(不知道),请参阅std::bitset - one reference

否则,是的,只需一个热点就可以将它们全部放在一个字节中。

答案 6 :(得分:0)

您可以尝试以下存储算法。它只需要一个6位的盒子。

class StorageBox
    {
        bool[] box = new bool[] { false, false, false, false, false, false };

        public void Addtobox(int number)
        {
            if (number<7 && number >0)
                box[number - 1] = true;
        }

        public string WhatIsinBox()
        {
            string result = "";

            for (int i = 0; i <= 5; i++)
            {
                if (box[i])
                    result = result + (i+1).ToString() + ",";

            }
            return result.Substring(0, result.Length - 1);
        }

        public void ClearBox()
        {
            box = new bool[] { false, false, false, false, false, false };
        }
    }


    class ExecuteSample
    {
        static void Main(string[] args)
        {
            var box = new StorageBox();

            box.Addtobox(5);
            box.Addtobox(3);
            box.Addtobox(4);

            Console.WriteLine(box.WhatIsinBox());

            Console.Read();
        }


    }