分组读取JSON数据

时间:2019-05-24 16:32:45

标签: c# json parsing

我有要读取JSON数据的JSON数据(有汽车的家庭)。一个子集如下所示:

[
   {
      "car":[
         "Honda Civic",
         "Toyota Camry"
      ]
   },
   {
      "car":[
         "Honda Civic"
      ]
   },
   {
      "car":[
         "BMW 760",
         "Mercedes S",
         "Smart Car"
      ]
   },
   {
      "car":[
         "Honda Odyssey",
         "Tesla X"
      ]
   },
   {
      "car":[
         "BMW 760"
      ]
   },
   {
      "car":[
         "Honda Odyssey",
         "Tesla X"
      ]
   },
   {
      "car":[
         "BMW 760"
      ]
   },
   {
      "car":[
         "Toyota Camry",
         "Honda Civic"
      ]
   }
]

当我使用以下逻辑读取文件时,文件读取成功。 (我正在使用Newtonsoft.Json。)

string sJSON = File.ReadAllText(@"D:\MyFolder\cars.json");
List<Car> allCars = JsonConvert.DeserializeObject<List<Car>>(sJSON);

Cars类是这样:

public class Car
{
    private ArrayList carNames = new ArrayList();

    public void AddCar(string carName)
    {
        carNames.Add(carName);
    }
}

我面临两个问题:

  1. 尽管JSON已成功读取,并且可以识别汽车名称,但未将其正确添加到allCars
  2. 我该如何计算汽车数量?例如:

    • 只有宝马760的家庭是3
    • 思域和凯美瑞都是2
    • 只有Civic是1,依此类推。

我试图做this question上提到的操作,但这没用。

3 个答案:

答案 0 :(得分:0)

首先必须拼合嵌套的汽车名称列表,然后将它们分组以获得所需的输出。

class Program
{
    static void Main(string[] args)
    {
        string carsData = @"
                        [
               {
                  'car':[
                     'Honda Civic',
                     'Toyota Camry'
                  ]
               },
               {
                  'car':[
                     'Honda Civic'
                  ]
               },
               {
                  'car':[
                     'BMW 760',
                     'Mercedes S',
                     'Smart Car'
                  ]
               },
               {
                  'car':[
                     'Honda Odyssey',
                     'Tesla X'
                  ]
               },
               {
                  'car':[
                     'BMW 760'
                  ]
               },
               {
                  'car':[
                     'Honda Odyssey',
                     'Tesla X'
                  ]
               },
               {
                  'car':[
                     'BMW 760'
                  ]
               },
               {
                  'car':[
                     'Toyota Camry',
                     'Honda Civic'
                  ]
               }
            ]
        ";

        List<Car> allCars = JsonConvert.DeserializeObject<List<Car>>(carsData);

        // Flatten all the car names first then group them
        var carDistributions = allCars.SelectMany(x => x.CarNames)
               .GroupBy(x => x, x => x, (key, x) => new
               {
                   CarName = key,
                   Count = x.Count()
               })
               .ToList();

        foreach (var carDistribution in carDistributions)
        {
            Console.WriteLine(carDistribution.CarName + " " + carDistribution.Count);
        }


    }
}

public class Car
{
    [JsonProperty("Car")]
    public List<string> CarNames { get; set; }
}

输出:

Honda Civic 3
Toyota Camry 2
BMW 760 3
Mercedes S 1
Smart Car 1
Honda Odyssey 2
Tesla X 2

答案 1 :(得分:0)

首先使用json2csharp或PasteSpecial选项创建用于json解析的模型。

您可以在编辑->选择性粘贴-> JSON作为类粘贴JSON

中找到

PasteSpecial选项。

enter image description here

这将为您提供正确的模型来解析json字符串,即

public class Car
{
    public List<string> car { get; set; }
}

现在,当您使用代码进行Json反序列化时,请使用相同的代码。

 List<Car> allCars = JsonConvert.DeserializeObject<List<Car>>(sJSON);

使用Linq SelectMany()where(),您可以根据其名称获得所有汽车记录,现在使用简单的Count(),您将从Json Array中获得每辆汽车的数量

 int count = allCars.SelectMany(x => x.car).Where(x => x == "Honda Civic").Count(); // It will return 3 as a result

答案 2 :(得分:0)

此JSON结果的本机数据类型为dotnet ef database update 20190524150901_initialll 。您可以直接使用以下方法进行解析:

List<Dictionary<string, string[]>>

然后您可以创建一些函数来搜索该数据:

var cars = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, string[]>>>(json);

如果您要将JSON中的数据重新组织到Households中,则可以执行以下操作:

private int HouseholdWith(List<Dictionary<string, string[]>> cars, string car1)
{
    return cars.Count(household => household["car"].Any(c => c == car1));
}

private int HouseholdWith(List<Dictionary<string, string[]>> cars, string car1, string car2)
{
    return cars.Count(household => household["car"].Any(c => c == car1) && household["car"].Any(c => c == car2));
}

private int HouseholdWithOnly(List<Dictionary<string, string[]>> cars, string car)
{
    return cars.Count(household => household["car"].All(c => c == car));
}

具有修改后的搜索功能:

class Household
{
    public List<string> Cars { get; set; }
}

var cars = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, string[]>>>(json);
List<Household> households = (
    from h in cars
    select new Household()
    {
        Cars = h["car"].ToList()
    }
).ToList();

并进行测试:

private int HouseholdsWith(List<Household> households, string car1)
{
    return households.Count(h => h.Cars.Any(c => c == car1));
}

private int HouseholdsWith(List<Household> households, string car1, string car2)
{
    return households.Count(h => h.Cars.Any(c => c == car1) && h.Cars.Any(c => c == car2));
}

private int HouseholdsWithOnly(List<Household> households, string car)
{
    return households.Count(h => h.Cars.All(c => c == car));
}

恕我直言,您对Newtonsoft的反序列化类应尽可能简单。 Newtonsoft功能强大,在反序列化过程中您可以做很多事情,但是它越简单,如果将来需要更改数据的结构,修改就越容易。反序列化后的映射功能是将数据转换为对应用程序有用的东西。我认为这是一个好的SoC原则。

奖励回合

Console.WriteLine("Households who have only BMW 760 are {0}", HouseholdsWithOnly(households, "BMW 760"));
//Households who have only BMW 760 are 2

Console.WriteLine("Households who have BMW 760 are {0}", HouseholdsWith(households, "BMW 760"));
//Households who have BMW 760 are 3

Console.WriteLine("Households with Civic and Camry are {0}", HouseholdsWith(households, "Honda Civic", "Toyota Camry"));
//Households with Civic and Camry are 2

Console.WriteLine("Households with only Civic is {0}", HouseholdsWithOnly(households, "Honda Civic"));
//Households with only Civic is 1

产生如下输出:

private void CreateReport(List<Household> households)
{
    //get all unique cars
    List<string> cars = households.SelectMany(h => h.Cars).Distinct().OrderBy(c => c).ToList();
    foreach(string c in cars)
    {
        Console.WriteLine("Households with {0}: {1}", c, HouseholdsWith(households, c));
        Console.WriteLine("Households with only {0}: {1}", c, HouseholdsWithOnly(households, c));
    }

    //Get each unique pair
    var pairs = households.Where(h => h.Cars.Count > 1).SelectMany(h =>
    {
        List<Tuple<string, string>> innerpairs = new List<Tuple<string, string>>();
        for (int i = 0; i < h.Cars.Count - 1; i++)
        {
            for (int j = i + 1; j < h.Cars.Count; j++)
            {
                if (string.Compare(h.Cars[i], h.Cars[j]) < 0)
                {
                    innerpairs.Add(new Tuple<string, string>(h.Cars[i], h.Cars[j]));
                }
                else
                {
                    innerpairs.Add(new Tuple<string, string>(h.Cars[j], h.Cars[i]));
                }
            }
        }
        return innerpairs;
    }).Distinct().ToList();

    foreach (var p in pairs)
    {
        Console.WriteLine("Households with {0} and {1}: {2}", p.Item1, p.Item2, HouseholdsWith(households, p.Item1, p.Item2));
    }
}