C# 存储六个单元的最小可能方式

C# 存储六个单元的最小可能方式,c#,bit-shift,C#,Bit Shift,如果我有数字1、2、3、4、5和6,并且我想以尽可能小的方式存储它们的一些组合,我该怎么做 例如,我可能想要存储1、4和5。或者可能是2、4、5和6。甚至可能是全部六个数字。我将始终至少有一个需要存储的号码。我想我可能已经看到了这一点与位转移完成,但我不完全理解它是如何工作的。值得一提的是,我在这里的最终目标是节省绝对最大的空间量,因为这些值需要存储在具有极少量存储空间的硬件设备上 编辑---------------------------------------- 谢谢大家的建议。我只是想澄清

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

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

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


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

不难想象,您可以将其存储在
bool
s的数组中。现在,考虑一下,什么是一点?一个位可以表示两种状态,就像一个
bool
。现在,整数是由位组成的。据我所知,C可用的最小值是
byte
。一个
字节有八位。您可以使用这些位中的一位来存储每个数字。让我们从最低有效位到最高有效位进行编号。我们可以将1存储在位0中,2存储在位1中,3存储在位2中,以此类推。现在我们有了数据的表示

[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
 }
}
我们如何打包数据?你提到了位偏移,你是对的。您可能希望使用位移位,但也可能需要使用一些其他操作;特别是,
~
(非)、
&
(和)和
|
(或)

总的来说,你会有这样的东西:

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));
字节标志=0;
//让我们加上2。
标志=1<P>如果C++可以处理C++ STL的东西(不知道),请参阅<代码> STD::BITSET  -< /P>

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

您说过需要节省空间,但没有提到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]);
}
或者,可以通过以下方式重写
GetFlags
的主体:

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

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

+--------+--------+--------+
|12345612|34561234|56123456|
+--------+--------+--------+
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;
}
要将值数组转换为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;
}
要将其中四个值合并为三个字节,请执行以下操作:

+--------+--------+--------+
|12345612|34561234|56123456|
+--------+--------+--------+
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;
}
公共静态字节[]PackCombinations(int[]值){
字节[]结果=新字节[3];
结果[0]=(字节)((值[0]>4));
结果[1]=(字节)((值[1]>2));

结果[2]=(字节)((值[2]您可以尝试以下存储算法。它只需要一个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();
        }


    }
类存储盒
{
bool[]框=新bool[]{false,false,false,false,false};
公共无效Addtobox(整数)
{
如果(数字0)
框[number-1]=真;
}
公共字符串WhatIsinBox()
{
字符串结果=”;

对于(int i=0;i+1,如果您将其更改为
public enum NumberEnum:byte
,它将全部放入一个字节中。另外,从.NET 4.0开始,对于所有
enum
值都有一个
hasvag()
扩展方法。您可以像这样使用它:
If(filterlags.hasvag(numbernum.One)){…}
您还可以使用按位或
运算符检查多个标志。
。如果您在运行时填充标志,那不是使用RAM吗?@icktoofay是的。作者没有说任何关于他的RAM的内容,只是关于他的存储。哦,我想我误解了您的评论。尽管如此,源代码会更简单,当然,但是您正在添加一些非平凡的依赖项:
字典
聚合
,例如。这些不太可能有微小的实现。@icktoofay同意。我最初的方法是在枚举上使用
标志
,但既然您都提到了这一点,我只想提供一些替代方法。除了上述方法之外e可以重写,使字典成为2xn矩阵,初始化可以写入
for
循环。谢谢你的例子!它为我澄清了很多关于移位和其他运算符的问题!你有关于未来使用不同组合的相对频率的信息吗?如果你有了这些信息,您有时可以将这31个不同的值平均存储在不到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();
        }


    }