用于创建锯齿状数组的 C# 函数

问题描述

我有一个问题,我想创建一个锯齿状数组。但是这个锯齿状数组的大小是可变的。 这与填充这样的普通数组的工作方式相同吗?

int[] terms = new int[400];
for (int runs = 0; runs < 400; runs++)
{
    terms[runs] = value;
}

我使用的值定义如下:

public static string[] nodeCassette0 = { "03","08" };
public static string[] nodeCassette1 = { "04","09" };
public static string[] nodeCassette2 = { "05","10" };
public static string[] nodeCassette3 = { "06","11" };
public static string[] nodeCassette4 = { "07","12" };

根据用户需要的大小,需要根据需要的大小填充一个新的变量nodeCassette。数组的填充顺序始终相同,从 0 开始,到 4 结束。

应该是这样,但是我不知道如何动态创建它:

public string[][] nodeCassette =
{ 
    nodeCassette0,nodeCassette1,nodeCassette2,nodeCassette3,nodeCassette4
};

解决方法

以下是如何创建这种锯齿状数组的示例:

int[] sizes = new int[] { 3,2,1,3 };

int[][] jagged = new int[sizes.Length][];

for (int i = 0; i < sizes.Length; i++)
{
    jagged[i] = new int[sizes[i]];
    for (int j = 0; j < sizes[i]; j++)
    {
        jagged[i][j] = (i + 1) * (j + 1);
    }
}

产生:

jagged


字符串没有什么不同:

int[] sizes = new int[] { 3,3 };

string[][] jagged = new string[sizes.Length][];

for (int i = 0; i < sizes.Length; i++)
{
    jagged[i] = new string[sizes[i]];
    for (int j = 0; j < sizes[i]; j++)
    {
        jagged[i][j] = $"{i}_{j}";
    }
}
,

我们可以使用反射和 Linq。

using System.Reflection;
using System.Linq;

默认使用这个专用类来存储数组,以及初始化可能元素的完整列表,并提供获取切片的方法,即由前 n 个元素组成的列表:

static class DefaultArrays
{
  static public string[] NodeCassette0 = { "03","08" };
  static public string[] NodeCassette1 = { "04","09" };
  static public string[] NodeCassette2 = { "05","10" };
  static public string[] NodeCassette3 = { "06","11" };
  static public string[] NodeCassette4 = { "07","12" };

  static public List<string[]> All { get; private set; }

  static public List<string[]> Take(int count)
  {
    return All.Take(count).ToList();
  }

  static public void Initialize()
  {
    All = typeof(DefaultArrays).GetFields()
                               .Where(field => field.FieldType == typeof(string[]))
                               .OrderBy(field => field.Name.Length)
                               .ThenBy(field => field.Name)
                               .Select(field => (string[])field.GetValue(null))
                               .ToList();
  }

  static DefaultArrays()
  {
    Initialize();
  }
}

Initialize 方法以这种方式创建,以便在运行时修改数组的情况下可能允许更新整个列表,否则代码可以直接放置在构造函数中,并且所有数组都标记为 readonly .

这是All的算法:

  • 我们通过类型名称获取静态类的所有字段。
  • 我们过滤以仅选择字符串数组类型的那些。
  • 我们按字段名称字符串长度排序。
  • 然后通过这个名字,我们最终从 40,30,1 中得到例如 1,40。
  • 我们进行投影以获取值的引用,而不是使用它的字段名称。
  • 然后我们将 Linq 查询转换为要返回的 List<string> 对象实例。

假设所有数组都已命名,它使用伪自然数字排序:

"[same_same][number_without_trailing_left_0]"

否则我们可以使用自定义比较器:

How do I sort strings alphabetically while accounting for value when a string is numeric?

sort string-numbers

测试

var slice = DefaultArrays.Take(3);

string msg = string.Join(Environment.NewLine,slice.Select(item => string.Join(",",item)));

Console.WriteLine(msg);

输出

03,08
04,09
05,10

警告

切片包含对原始数组的引用列表,因此对该列表中数组单元格的任何修改都将反映在静态类中的匹配数组中。

否则我们需要使用 Array.Copy 而不是使用 Linq.Take 复制数组:

  static public List<string[]> TakeCopy(int count)
  {
    var list = new List<string[]>();
    foreach ( int index in Enumerable.Range(0,Math.Min(count,All.Count)))
    {
      int length = All[index].Length;
      var array = new string[length];
      Array.Copy(All[index],array,length);
      list.Add(array);
    }
    return list;
  }