使用Newtonsoft.Json将两个数组转换为一个JSON对象

7
我有两个数组name[]lastname[]。我该如何将它们合并并转换为JSON字符串?我希望它的格式如下所示,并在JSON中包含“Employees”标题。
{ "Employees" : [
    {"name": "John", "lastname": "Coleman"},
    {"name": "Chip", "lastname": "Dale"},
    {"name": "Ann", "lastname": "Smith"},
    {"name": "Terry", "lastname": "Johnson"},
    {"name": "Mary", "lastname": "Loggins"},
    {"name": "Timothy", "lastname": "Lopez"},
    {"name": "Jessica", "lastname": "Brown"}
]}

我需要一种高效的方法来完成这项任务,因为数组中有很多项。实际上,我有两个以上的数组需要合并成一个JSON对象。为了简单起见,我用两个数组演示了我想要的结果。它们都有相同数量的项目,并且已排序。我不想迭代数组并自己构造JSON字符串。
更新:我忘了提到我的数组是IEnumerable<[]>,包括字符串和整数数组。以下是我尝试过的内容,这些数组是在另一个类中创建的。
  public string[] Name {
                get{ return  (Employees ?? Enumerable.Empty<Employee> ()).Select (p => p.name).ToArray(); }
            }

    public string[] Lastname {
                get{ return  (Employees ?? Enumerable.Empty<Employee> ()).Select (p => p.lastname).ToArray(); }
            }

    public int[] Age {
                get{ return  (Employees ?? Enumerable.Empty<Employee> ()).Select (p => p.age).ToArray(); }
            }

I then access them

var name = X.Select(s => s.Name).ToArray();
var lastname = X.Select(s => s.Lastname).ToArray();
var age = X.Select(s => s.Age).ToArray();

var employees = new { Employees = Enumerable.Range(0, name.Length).Select(i => new { name = name[i], lastname = lastname[i], age = age[i] }) };
var json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Debug.WriteLine(json);

由于某些原因,这会返回类似于以下内容:
{"Employees":[{"name":["John","Chip","Ann","Terry"],"lastname":["Coleman","Dale","Smith","Johnson"],"age":[42, 26, 33, 24]}]}

所有的名字和姓氏都放在一起了。我该如何获得正确的格式?


请展示你的 namelastname 数组。 - Sumner Evans
在更新后的示例中,X是什么?它是包含员工列表的类的可枚举对象吗? - dbc
这是一个不同的反序列化JSON对象。 - Carell
它是一个对象还是包含属性 public string[] Namepublic string[] Lastnamepublic int[] Age 的对象枚举?如果是这样,那么你有的是字符串数组的数组,而不是字符串数组。你需要使用 SelectMany 等方法将它们展开。 - dbc
是的,它是包含属性的可枚举对象。如果我执行 public string[] Name { get{ return (Employees ?? Enumerable.Empty<Employee> ()).SelectMany (p => p.name); } } 我会得到错误 Error CS0411: 无法从用法推断出方法 `System.Linq.Enumerable.SelectMany<TSource,TResult>(this System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,System.Collections.Generic.IEnumerable<TResult>>)' 的类型参数。请尝试显式指定类型参数。 - Carell
1个回答

7

您可以使用Zip()将它们与一个匿名类型组合,然后对其进行序列化:

        string[] name = new string[] { "John", "Chip" };
        string[] lastname = new string[] { "Coleman", "Dale" };

        var employees = new { Employees = name.Zip(lastname, (n1, n2) => new { name = n1, lastname = n2 }) };
        var json = JsonConvert.SerializeObject(employees, Formatting.Indented);
        Debug.WriteLine(json);

这将输出:

{
  "Employees": [
    {
      "name": "John",
      "lastname": "Coleman"
    },
    {
      "name": "Chip",
      "lastname": "Dale"
    }
  ]
}

对于多个数组,使用Enumerable.Range()可以更容易地并行迭代这些数组:

        string[] name = new string[] { "John", "Chip" };
        string[] lastname = new string[] { "Coleman", "Dale" };
        string[] title = new string[] { "Mr", "Dr" };
        string[] profession = new string[] { "Coder", "Doctor" };

        var employees2 = new { Employees = Enumerable.Range(0, name.Length).Select(i => new { title = title[i], name = name[i], lastname = lastname[i], profession = profession[i] }) };
        var json2 = JsonConvert.SerializeObject(employees2, Formatting.Indented);
        Debug.WriteLine(json2);

更新

如果你的字符串在一个 IEnumerable<String[]> 中,你可以将外部可枚举对象转换为数组然后索引它。例如,给定以下测试用例:

        string[] name = new string[] { "John", "Chip" };
        string[] lastname = new string[] { "Coleman", "Dale" };
        string[] title = new string[] { "Mr", "Dr" };
        string[] profession = new string[] { "Coder", "Doctor" };

        IEnumerable<string[]> strings = new[] { title, name, lastname, profession };

您可以执行以下操作:

        var stringArray = strings.ToArray();

        var employees2 = new { Employees = Enumerable.Range(0, name.Length).Select(i => new { title = stringArray[0][i], name = stringArray[1][i], lastname = stringArray[2][i], profession = stringArray[3][i] }) };
        var json2 = JsonConvert.SerializeObject(employees2, Formatting.Indented);
        Debug.WriteLine(json2);

这导致:
{
  "Employees": [
    {
      "title": "Mr",
      "name": "John",
      "lastname": "Coleman",
      "profession": "Coder"
    },
    {
      "title": "Dr",
      "name": "Chip",
      "lastname": "Dale",
      "profession": "Doctor"
    }
  ]
}

更新 2

如果您实际上有一个包含员工枚举的对象枚举,您可以使用Enumerable.SelectMany将它们展开。例如,给定以下类:

public class Employee
{
    public string name { get; set; }
    public string lastname { get; set; }
    public int age { get; set; }
    public string someMoreDataThatShouldNotBeSerialized { get; set; }
}

public class EmployeeContainer
{
    public IEnumerable<Employee> Employees { get; set; }
}

您可以按如下方式压平它们:
        var X = GetAllEmployees();

        var employees = X.SelectMany(s => s.Employees ?? Enumerable.Empty<Employee>()).Select(e => new { name = e.name, lastname = e.lastname, age = e.age });
        var json = JsonConvert.SerializeObject(employees, Formatting.Indented);
        Debug.WriteLine(json);

接下来是测试设置

    public static IEnumerable<EmployeeContainer> GetAllEmployees()
    {
        return new[] { 
            new EmployeeContainer { 
                Employees = 
                    new[] { 
                        new Employee { name = "John", lastname = "Coleman", age = 42, someMoreDataThatShouldNotBeSerialized = "someMoreData1" },
                        new Employee { name = "Chip", lastname = "Dale", age = 26, someMoreDataThatShouldNotBeSerialized = "someMoreData2" },
                    } 
            },
            new EmployeeContainer { 
                Employees = 
                    new[] { 
                        new Employee { name = "Ann", lastname = "Smith", age = 33, someMoreDataThatShouldNotBeSerialized = "someMoreData3" },
                        new Employee { name = "Terry", lastname = "Johnson", age = 24, someMoreDataThatShouldNotBeSerialized = "someMoreData4" }, 
                    } 
            },
            new EmployeeContainer()
        };
    }

产生:

[
  {
    "name": "John",
    "lastname": "Coleman",
    "age": 42
  },
  {
    "name": "Chip",
    "lastname": "Dale",
    "age": 26
  },
  {
    "name": "Ann",
    "lastname": "Smith",
    "age": 33
  },
  {
    "name": "Terry",
    "lastname": "Johnson",
    "age": 24
  }
]

使用.NET Fiddle进行编程。


这个方法能处理超过2个数组吗?Zip()只接受两个数组作为参数。如果有7个或更多的数组,你会运行多个Zip()吗?是否有更优雅的解决方案? - Daniel Hoffmann-Mitscherling
@DanielHoffmann-Mitscherling - 既然它们是数组,你可以使用 Enumerable.Range(0, array0.Length).Select(i => new { a = array0[i], b = array1[i], c = array2[i], ... })。否则就需要多个 zip 操作,或者创建一个带有多个输入的扩展方法。 - dbc
1
第一个很明显,但作者要求不要迭代数组,然而Zip()仍然会这样做(但你不必为此编写代码)。我不知道他/她试图尝试什么。好的是你可以串联多个Zips!(虽然扩展方法更好) - Daniel Hoffmann-Mitscherling
1
@DanielHoffmann-Mitscherling - 我的理解是OP 不想编写手动的 foreach 循环。在某个代码层面上(也许是Json.NET本身),需要访问每个数组元素。 - dbc
1
@dbc 同意!顺便说一句,你对回答的编辑使它变成了一个很棒的答案。 - Daniel Hoffmann-Mitscherling
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接