Упрощение нескольких (не вложенных) циклов foreach в c# - PullRequest
2 голосов
/ 10 января 2020

У меня есть JSON объект:

"Cars": {
 "Honda": {
   "CRV": [

     { "index": 1, "Color": "Black" },
     { "index": 2, "Color": "White" }

    ],
    "Civic": [

     { "index": 1, "Color": "Blue" }

    ]
   },
  "Toyota": {
   "Corolla": [

     { "index": 1, "Color": "Black" }

    ],
    "Camry": [

     { "index": 1, "Color": "Blue" }

    ]
   },
  "GM": {
   "Chevrolet": {

     "Cruze": [

       { "index": 1, "Color": "Blue" }

    ]

    }
 }

Я должен сохранить эту информацию в таблице. Прямо сейчас я анализирую каждый список в отдельности для каждого l oop, например:

 foreach (CarInfo info in Cars.Honda.CRV)
  {
                //storing in table
  }
  foreach (CarInfo info in Cars.Honda.Civic)
  {
                //storing in table
  }
 foreach (CarInfo info in Cars.Toyota.Corolla)
  {
                //storing in table
  }

и так далее. Есть ли способ, которым я мог бы оптимизировать этот код? (Это просто пример, фактический JSON является более обширным и заставил меня написать слишком много циклов foreach)

Метод хранения информации в таблице различен для каждой марки автомобиля.

Ответы [ 3 ]

1 голос
/ 11 января 2020

Поскольку у вас нет контроля над вводом JSON, вот подход, аналогичный моей последней рекомендации, который анализирует входящие JSON, включая поддержку подмоделей GM.

static void Main(string[] args)
{
    // parse the JSON results of the API Call
    JObject apiResult = JObject.Parse(File.ReadAllText("JsonBlock.json"));
    // iterate through the models
    foreach (var model in apiResult["Cars"].Children<JProperty>().Select(i => i.Name))
        // GM cars have a submodel
        if(model.Equals("GM",StringComparison.CurrentCultureIgnoreCase)) 
        {
            foreach (var submodel in apiResult["Cars"][model].Children<JProperty>().Select(i => i.Name))
                AddCar(submodel,apiResult["Cars"][model][submodel]);
        } 
        else
            AddCar(model,apiResult["Cars"][model]);            
}

static void AddCar(string model, JToken cars)
{
    switch(model)
    {
        case "Honda":                    
            // do honda things
            break;
        case "Toyota":
            // do toyota things
            break;
        case "Chevrolet":
            // do chevy things
            break;
        default:
            throw new NotImplementedException();
    }            
}
1 голос
/ 10 января 2020

Вы управляете форматом исходных данных?

  • Как уже упоминалось в 3Dave, вы будете намного счастливее, если марка автомобиля и модель будут значениями вместо ключей.
  • I Можно добавить, что у вас есть один объект «Автомобили». Возможно, вам будет намного проще управлять этим, если у вас есть массив объектов «Car», каждый из которых имеет свои внутренние атрибуты.
{ "Cars": [
  { "make": "honda",
    "model": "CRV",
    "attributes": ["index":1,"color":"blue"]
  },
  { "make": "honda",
    "model": "CRV",
    "attributes": ["index":2,"color":"white"]
  },
  { "make": "honda",
    "model": "Civic",
    "attributes": ["index":1,"color":"black"]
  }
]}

Это упрощает свертывание вашей итерации до один foreach l oop, затем обрабатывает другой метод для хранения в таблице в подпрограмме:

void AddAllCars()
{
  foreach (var car in Cars)
    AddCar(car);
}

void AddCar(CarInfo car)
{
    switch(car.Make)
    {
      case "honda":
        // honda-specific stuff
        break;
      case "toyota":
        // toyota-specific stuff
        break;
    }
}

(Note that even if you can't reformat into an array of Cars, you can still make big improvements by changing make and model to values instead of keys)

0 голосов
/ 10 января 2020

Как на счет этого ... Рекурсивный подход, так как ваши классы не совпадают с Cars / Make / Model, у вас есть Cars // Make / Model.

  1. Разобрать Json для JObject
  2. Создайте словарь для каждого Make , чтобы вы могли сохранять их отдельно через отдельный процесс
    public static Dictionary<string, List<CarInfo>> GetCarInfo (JObject jObject)
    {
        Dictionary<string, List<CarInfo>> list = new Dictionary<string, List<CarInfo>>();
        foreach (var property in jObject.Properties())
        {
            var thisProp = jObject[property.Name];
            if (thisProp.Type.ToString().Equals("Array"))
                    list.Add(property.Name, JsonConvert.DeserializeObject<List<CarInfo>>(thisProp.ToString()));
            else
                GetCarInfo((JObject)jObject[property.Name]).ToList().ForEach(x => list.Add(x.Key, x.Value));

            }
        return list;
    }

    public static void SaveData(string key, List<CarInfo> value)
    {
        switch (key.ToUpper())
        {
            case "CRV":
                // save it the CRV way
                break;

            case "COROLLA":
                // save it this way
                break;

            default:
                throw new ApplicationException("Unable to figure out which car it is..");
        }
    }

Использование в Main

    var cars = JObject.Parse(json);
    Dictionary<string, List<CarInfo>> carInfos = GetCarInfo((JObject)cars["Cars"]);
    foreach (var carInfo in carInfos)
        SaveData(carInfo.Key, carInfo.Value);

Примечание

Я заметил, что ваш объект json действительно не соответствует тому же стандарту. У вашего GM есть две материнские компании, когда у Honda и Toyota одна.

Предложение

Единственное, что я бы посоветовал, чтобы код выглядел и работал лучше, это обновить способ Вы звоните, чтобы обновить / добавить в БД. В настоящее время у вас есть один вызов для каждого типа, который определяет ваши циклы foreach. Если вы можете создать один обобщенный метод c для сохранения «CarInfo» с другим аргументом, который определяет «CRV» или «CORROLLA», это значительно упростит вам задачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...