0

我昨天开始的“地狱般的”项目之一是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

与其重新创建整个锯齿状数组(假设它可能相当大),不如为它创建一个包装器。该包装器将能够进行边界检查并返回一些默认值,如果它超出边界而不是错误。

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 回答
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 回答
0

Man, I'm not sure if this is what you're looking for, but check this out:

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

Usage:

        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();

Any feedback will be appreciated.


UPDATE

Nicholas pointed out the performance issue. I was curious about it, so I made the following micro-weak-benchmarking:

        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();

I've run it multiple times, and the average results was:

Andre Calil: 3 ms
Nicholas Carey: 5 ms

I know that this is not a proper benchmarking, but looke like my solution isn't so bad in terms of performance after all.

于 2012-08-17T19:24:33.983 回答