【问题标题】:C# - convert a list of objects to an array of multiple of the object's propertiesC# - 将对象列表转换为包含多个对象属性的数组
【发布时间】:2021-02-15 22:54:08
【问题描述】:

我有这个 JSON 字符串:

{
  "countries": [
    {
      "countryCode": "AR",
      "country": "Argentina"
    },
{
      "countryCode": "BR",
      "country": "Brazil"
    }
  ]
}

还有这个 Country 类和国家列表:

List<Country> countries { get; set; }
class Country
    {
        public string country { get; set; }
        public string countryCode { get; set; }
    }

我需要创建一个包含国家代码和名称的二维对象数组:

propVal[0, 0] = "AR";
propVal[0, 1] = "Argentina";
propVal[1, 0] = "BR";
propVal[1, 1] = "Brazil";
.
.
.

现在我正在“手动”遍历国家列表并构建对象数组:

int row = 0;
foreach (Country country in countries)
{
    propVal[row, 0] = country.countryCode;
    propVal[row, 1] = country.country;
    row++;
}

远景是有一个通用的方式,适用于其他 JSON,假设有 3 个或更多属性,并产生一个 x 维对象数组。 有没有一种 LINQ 方法可以做到这一点?我知道this 线程,它处理一个对象属性并且LINQ 方法是countries.Select(x=&gt;x.country).ToArray(),但在我的情况下需要多个属性。

感谢您的帮助!

【问题讨论】:

  • 这似乎是一个 X/Y 问题。为什么你需要一个多维数组,而不是一个类(国家)列表
  • 因为生成的多维对象数组会写入Excel表格。
  • 你可以使用反射来做到这一点。但它不会很漂亮......使用DataTable怎么样?
  • 没有内置的 linq 方法来生成多维数组 - 这有一个很好的理由:数组的维数必须在编译时知道 - 所以你不能有一个方法可以返回一个任意维数的数组。方法可以做到这一点的唯一方法是返回 dynamicobject - 这为各种问题打开了大门 - 主要问题是应该是编译时错误的错误被推送到运行时。
  • 正常序列化,然后循环填充二维数组。你也可以喜欢 JObject,但我不会打扰。像往常一样序列化它

标签: c# arrays linq object


【解决方案1】:

如果你真的需要构建一个二维数组,你可以通过这种方式动态排列数据:

var data = new List<Country>
{
    new Country {country = "Brazil", countryCode = "BR"},
    new Country {country = "Argentina", countryCode = "AR"}
};

// declare all the property accessors you want from your type (Country)
// it can be built by reflection
var accessors = new List<Func<Country, string>>
{
    x => x.country,
    x => x.countryCode
};

// declaring the 2D array,
//   first dimension length is the size of the data (number of countries)
//   second dimension length is the number of fields from the data type (Country)
var propVal = new string[data.Count, accessors.Count];

// projecting each element with each field accessor (cartesian product)
// that is (countries.Count) x (accessors.Count)
// (0,0,"Brazil") (0,1,"BR") (1,0,"Argentina") (1,1,"AR")
var flatenData = data.SelectMany((country, i) => accessors.Select((f, j) => (i, j, field: f(country))));

// filling the 2D array
foreach (var tuple in flatenData)
{
    propVal[tuple.i, tuple.j] = tuple.field;
}

如果我们显示二维数组:

// displaying the 2D array
for (var i = 0; i < propVal.GetLength(0); i++)
{
    for (var j = 0; j < propVal.GetLength(1); j++)
    {
        Console.WriteLine($"[{i},{j}] = {propVal[i,j]}");
    }
}

/*
[0,0] = Brazil
[0,1] = BR
[1,0] = Argentina
[1,1] = AR
*/

【讨论】:

    【解决方案2】:

    我建议从多维数组切换到数组数组 - 它更容易实现,并且很可能满足您在此任务中的所有需求。

    这是您需要做的。假设您有一些具有一堆公共属性的通用类,您希望以这种方式序列化:

        public class A
        {
            public string P1 {get; set;}
            public string P2 {get; set;}
            public string P3 {get; set;}
        }
    

    您可以像这样获取该类的属性集合:

        var props = typeof(A).GetProperties();
    

    然后,您需要做的就是对您的项目集合进行 LINQ 并获取每个属性的值:

    var result = items.Select(item => 
                         props.Select(prop => 
                           prop.GetValue(item)
                               .ToString())
                              .ToArray())
                      .ToArray();
    

    当然,itemsList&lt;A&gt;

    就是这样。你有自己的数组。

    如果你觉得你确实需要它是一个 2D 数组,那么你必须像 here 那样实现转换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-18
      • 1970-01-01
      • 2019-02-10
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多