0

私が昨日始めた「めちゃくちゃ」なプロジェクトの 1 つは、Befungeインタープリターでした。エッジケースを除いて、ほとんどの場合動作しています。

私は怠け者になり、これでbefungeプログラムを読むことにしました:

char[][] program = File.ReadAllLines(args[0]).Select(x => x.ToCharArray()).ToArray();

後で自分のためにもっと作品を作ることはわかっていましたが、他の部分に取り掛かりたかったので、そのままにしておきました。今は後で、program長方形ではないという事実を修正する必要があります。私がこのbefungeプログラムを持っていたとしましょう:

v   v   <
    @
>       ^

1 行目と 3 行目は 9 文字の長さですが、2 行目はわずか 5 文字です。befunge インタープリターをセットアップした方法ではIndexOutOfBoundsException、プログラムが終了する前に を取得^します。長program[1][8]program[1]はわずか5です。例外をキャッチしてその周りで踊ろうとする代わりに、余分な文字をchar[,]使用programしてスペースで埋める方法を作成するにはどうすればよいですか?

最長の行の長さ、行数を特定し、それらを使用して char[,] を作成し、それらをコピーするだけでよいことはわかっていますが、もう少しシンプルでエレガントなものを望んでいます。新しいアプローチの方が優れている場合は、上記の行を破棄しても問題ありません。

4

3 に答える 3

2

Building on @AndreCalil's previous answer, this might be more performant, especially for large arrays of primitive types. Arrays of primitive types can be treated as a flat buffer of bytes, which can be useful in this sort of work (if you've got experience with assembler or C):

static void Main( string[] args )
{
    string[][] jagged = new string[][] { new string[] { "alpha" ,                                              } ,
                                            new string[] { "bravo" , "charlie" ,                                  } ,
                                            new string[] { "delta" , "echo"    , "foxtrot" ,                      } ,
                                            new string[] { "golf"  , "hotel"   , "india"   , "juliet" ,           } ,
                                            new string[] { "kilo"  , "lima"    , "mike"    , "nancy"  , "oscar" , } ,
                                        } ;
    string[,]  rectangular = RectArrayFromJagged<string>( jagged ) ;

    return;
}

public static T[,] RectArrayFromJagged<T>( T[][] a )
{
    int  rows  = a.Length;
    int  cols  = a.Max( x => x.Length );
    T[,] value = new T[ rows , cols ] ;

    value.Initialize() ;

    if ( typeof(T).IsPrimitive )
    {
        int elementSizeInOctets = Buffer.ByteLength(value) / value.Length ;
        for ( int i = 0 ; i < rows ; ++i )
        {
            int rowOffsetInOctets = i * cols    * elementSizeInOctets ;
            int rowLengthInOctets = a[i].Length * elementSizeInOctets ;
            Buffer.BlockCopy( a[i] , 0 , value , rowOffsetInOctets , rowLengthInOctets ) ;
        }
    }
    else
    {
        for ( int i = 0 ; i < rows ; ++i )
        {
            int rowLength = a[i].Length ;
            for ( int j = 0 ; j < rowLength ; ++j )
            {
                value[i,j] = a[i][j] ;
            }
        }
    }
    return value ;
}
于 2012-08-17T20:44:25.447 に答える
2

ギザギザの配列全体を再作成するのではなく (かなり大きくなる可能性があると仮定して)、そのラッパーを作成するだけで済みます。そのラッパーは、境界チェックを実行し、エラーではなく境界外の場合にデフォルト値を返すことができます。

public class Matrix<T>
{
  public T[][] UnderlyingCollection {get;set;} //should probably be readonly and set in the constructor

  public T DefaultValue {get;set;}

  public T this[int i, int j]
  {
    get
    {
      if(UnderlyingCollection.Length > i && UnderlyingCollection[i].Length > j)
        return UnderlyingCollection[i][j];
      else
        return DefaultValue;
    }
    set
    { /*TODO implement*/ }

  }
}
于 2012-08-17T18:30:30.457 に答える
0

男、これがあなたが探しているものかどうかはわかりませんが、これをチェックしてください:

public static class CharArrayExtension
{
    public static char[,] FormatMatrix(this char[][] matrix)
    {
        int TotalColumns = matrix.Length;
        int TotalLines = 0;

        //Get the longest line of the current matrix
        for (int column = 0; column < TotalColumns; column++)
        {
            int line = matrix[column].Length;

            if (line > TotalLines)
                TotalLines = line;
        }

        //Instantiate the resulting matrix
        char[,] Return = new char[TotalColumns, TotalLines];

        Return.Initialize();

        //Retrieve values from the current matrix
        for (int CurrentColumn = 0; CurrentColumn < TotalColumns; CurrentColumn++)
        {
            int MaxLines = matrix[CurrentColumn].Length;

            for (int CurrentLine = 0; CurrentLine < MaxLines; CurrentLine++)
            {
                Return[CurrentColumn, CurrentLine] = matrix[CurrentColumn][CurrentLine];
            }
        }

        return Return;
    }
}

使用法:

        char[] Length5 = new char[]{ 'a', 'b', 'c', 'd', 'e'};
        char[] Length10 = new char[10];

        char[][] Matrix = new char[2][];
        Matrix[0] = Length5;
        Matrix[1] = Length10;

        char[,] FormattedMatrix = Matrix.FormatMatrix();

フィードバックをお待ちしております。


アップデート

Nicholas はパフォーマンスの問題を指摘しました。私はそれについて興味があったので、次のマイクロウィークベンチマークを作成しました。

        char[] Length5 = new char[]{ 'a', 'b', 'c', 'd', 'e'};
        char[] Length10 = new char[10];

        char[][] Matrix = new char[2][];
        Matrix[0] = Length5;
        Matrix[1] = Length10;

        Stopwatch stopWatch = new Stopwatch();

        stopWatch.Start();

        for (int i = 0; i < 5000; i++)
        {
            char[,] FormattedMatrix = Matrix.FormatMatrix();
        }

        stopWatch.Stop();

        Console.WriteLine(string.Format("Andre Calil: {0} ms", stopWatch.ElapsedMilliseconds));

        stopWatch.Reset();

        stopWatch.Start();

        for (int i = 0; i < 5000; i++)
        {
            char[,] FormattedMatrix = RectArrayFromJagged<char>(Matrix);
        }

        stopWatch.Stop();

        Console.WriteLine(string.Format("Nicholas Carey: {0} ms", stopWatch.ElapsedMilliseconds));

        Console.ReadLine();

何度も実行しましたが、平均結果は次のとおりです。

Andre Calil: 3 ms
Nicholas Carey: 5 ms

これが適切なベンチマークではないことはわかっていますが、結局のところ、私のソリューションはパフォーマンスの点でそれほど悪くないようです。

于 2012-08-17T19:24:33.983 に答える