2

1、2、3、4、5、6の番号があり、それらの組み合わせを可能な限り最小の方法で保存したい場合、どうすればよいですか?

たとえば、1、4、5、または2、4、5、6を格納したい場合があります。あるいは、6つの数値すべてを格納したい場合もあります。保存する必要のある番号は常に少なくとも1つあります。これがビットシフトで達成されたのを見たことがあると思いますが、それがどのように機能するかを完全には理解していません。これらの値は非常に少量のストレージスペースを持つハードウェアデバイスに保存する必要があるため、ここでの私の最終的な目標は、絶対最大量のスペースを節約することです。

編集 - - - - - - - - - - - - - - - - - - - -

すべての素晴らしい提案をみんなに感謝します。私のアプリケーションの実装は、必ずしも可能な限り小さくする必要はなく、私が理解していて、私の後ろにいる別の開発者にとって意味のあるものである必要があることを明確にしたかっただけです。最も重要なことは、これらの値を可能な限り最小の方法で表現できることです。最終的には、他のいくつかの値を使用してバイト配列を作成し、ストレージが非常に限られているデバイスにすべてを書き込む必要があるためです。素晴らしい提案をありがとうございました!

4

7 に答える 7

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
 }
}
于 2013-01-14T00:26:53.127 に答える
1

これをsの配列に格納できることを想像するのはそれほど難しいことではありませんbool。さて、考えてみてください、少し何ですか?ビットは、のように2つの状態を表すことができboolます。現在、整数はビットで構成されています。私が知っているC#で利用できる最小のものはですbyte。Abyteは8ビットです。保存する必要のある数値ごとに、これらのビットの1つを使用できます。最下位から最上位までビットに番号を付けましょう。1をビット0に、2をビット1に、3をビット2に、というように格納できます。これで、データの表現ができました。

データをどのようにパックしますか?あなたはビットシフトについて言及しました、そしてあなたは正しいでしょう。おそらくビットシフトを使用したいと思うでしょうが、おそらく他のいくつかの操作も使用する必要があります。特に、~(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を取得できます。2バイトをOR演算すると、セットの和集合が取得されます。ANDingは交差点を取ります。からa & ~b設定されたすべてのビットを削除します。ba

于 2013-01-14T00:29:47.747 に答える
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;
于 2013-01-14T00:32:03.120 に答える
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() + "!");
于 2013-01-14T00:37:49.080 に答える
1

1バイトの6ビットを使用して組み合わせを格納できます。つまり、各バイトに組み合わせの1と3分の1を格納するか、3バイトに4つの組み合わせを格納できます。

+--------+--------+--------+
|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;
}

これらの値の4つを3バイトに結合するには:

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;
}
于 2013-01-14T00:49:15.160 に答える
0

C#がC ++ STLのものを処理できる場合std::bitset(わかりません)、 - 1つのリファレンスを参照してください。

そうでなければ、ええ、ちょうどホットビットはそれらすべてを1バイトに収めるでしょう。

于 2013-01-14T00:30:57.867 に答える
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();
        }


    }
于 2013-01-18T17:30:13.463 に答える