簡體   English   中英

將JObject轉換為多維數組

[英]Convert JObject to multi-dimensional array

如何將JObject轉換為3D數組? 我有一個這樣格式化的JObject:

{
  "0": [
    [
      1.0,
      2.0,
      3.0
    ],
    [
      4.0,
      5.0,
      6.0
    ]
  ],
  "1": [
    [
      7.0,
      8.0,
      9.0
    ],
    [
      10.0,
      11.0,
      12.0
    ]
  ]
}

我嘗試將其強制轉換為double[,,]但失敗並顯示錯誤

Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'System.Double[,,]'.

以下對我有用:

var deserailizationExp = JsonConvert.DeserializeObject<Dictionary<string, double[,]>>(@"
          {""0"": [
            [
              1.0,
              2.0,
              3.0
            ],
            [
              4.0,
              5.0,
              6.0
            ]
          ],
          ""1"": [
            [
              7.0,
              8.0,
              9.0
            ],
            [
              10.0,
              11.0,
              12.0
            ]
          ]
        }");

然后,您可以直接使用字典,也可以將其轉換為數組。 編輯:正如對此評論中所指出的那樣,您也可以考慮將其反序列化為SortedDictionary<int, double[,]> 我將其作為一種類型進行了測試,並且對我有用。

另外,如果您修改JSON,則可以執行以下操作:

var otherDes = JsonConvert.DeserializeObject<double[,,]>(@"
          [[
            [
              1.0,
              2.0,
              3.0
            ],
            [
              4.0,
              5.0,
              6.0
            ]
          ],
          [
            [
              7.0,
              8.0,
              9.0
            ],
            [
              10.0,
              11.0,
              12.0
            ]
          ]
        ]");

如您所見,我剛剛刪除了“ 0”和“ 1”,並將{}替換為[]。 如果您能夠控制以某種方式接收JSON的方式,那么我認為這可能是更好的解決方案,因為它與您請求的類型匹配,而無需對其進行任何進一步的操作。

Json.NET希望多維數組的格式類似於JSON文件中的3d鋸齒狀數組,但是您的格式像2d鋸齒狀數組的字典一樣。 您可以使用自定義JsonConverter將這種格式的JSON轉換為3d數組,如下所示:

public class Array3DConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        if (!objectType.IsArray)
            return false;
        return objectType.GetArrayRank() == 3;
    }

    object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        if (reader.TokenType == JsonToken.StartArray)
        {
            // Handle case when it's actually a 3d array in the JSON.
            var list = serializer.Deserialize<List<List<List<T>>>>(reader);
            return list.Select((l, i) => new KeyValuePair<int, List<List<T>>>(i, l)).To3DArray();
        }
        else if (reader.TokenType == JsonToken.StartObject)
        {
            // Handle case when it's a dictionary of key/value pairs.
            var dictionary = serializer.Deserialize<SortedDictionary<int, List<List<T>>>>(reader);
            return dictionary.To3DArray();
        }
        else
        {
            throw new JsonSerializationException("Invalid reader.TokenType " + reader.TokenType);
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        try
        {
            var elementType = objectType.GetElementType();
            var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            return method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { reader, objectType, existingValue, serializer });
        }
        catch (TargetInvocationException ex)
        {
            // Wrap the TargetInvocationException in a JsonSerializerException
            throw new JsonSerializationException("Failed to deserialize " + objectType, ex);
        }
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class EnumerableExtensions
{
    public static T[,,] To3DArray<T>(this IEnumerable<KeyValuePair<int, List<List<T>>>> jaggedArray)
    {
        if (jaggedArray == null)
            throw new ArgumentNullException("jaggedArray");
        var counts = new int[3];
        foreach (var pair in jaggedArray)
        {
            var i = pair.Key;
            counts[0] = Math.Max(i + 1, counts[0]);
            if (pair.Value == null)
                continue;
            var jCount = pair.Value.Count;
            counts[1] = Math.Max(jCount, counts[1]);
            for (int j = 0; j < jCount; j++)
            {
                if (pair.Value[j] == null)
                    continue;
                var kCount = pair.Value[j].Count;
                counts[2] = Math.Max(kCount, counts[2]);
            }
        }
        var array = new T[counts[0], counts[1], counts[2]];
        foreach (var pair in jaggedArray)
        {
            var i = pair.Key;
            if (pair.Value == null)
                continue;
            var jCount = pair.Value.Count;
            for (int j = 0; j < jCount; j++)
            {
                if (pair.Value[j] == null)
                    continue;
                var kCount = pair.Value[j].Count;
                for (int k = 0; k < kCount; k++)
                    array[i, j, k] = pair.Value[j][k];
            }
        }
        return array;
    }
}

然后像這樣使用它:

var array = JsonConvert.DeserializeObject<double[, ,]>(jsonString, new JsonSerializerSettings { Converters = new[] { new Array3DConverter() } });

或者,如果您已經將JSON字符串解析為JObject ,則可以使用JToken.ToObject<T>(JsonSerializer)使用轉換器將其反序列化為所需的類型:

var array = jObj.ToObject<double[, ,]>(JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = new[] { new Array3DConverter() } }));

為了靈活使用,轉換器進行測試以查看傳入的JSON是否被格式化為對象或數組,並做出適當的響應。

注意-僅經過輕微測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM