python как искать строку, подсчитывать значения и группировать по json - PullRequest
1 голос
/ 15 марта 2020

У меня есть программа python, вызывающая API, который получает результат, как показано ниже:

{
   "result": [
       {
         "company" : "BMW",
         "model" : "5"
       },           
       {
         "company" : "BMW",
         "model" : "5"
       },           
       {
         "company" : "BMW",
         "model" : "5"
       },           
       {
         "company" : "BMW",
         "model" : "3"
       },           
       {
         "company" : "BMW",
         "model" : "7"
       },           
       {
         "company" : "AUDI",
         "model" : "A3"
       },           
       {
         "company" : "AUDI",
         "model" : "A7"
       },           
]
}

Теперь моя задача - определить количество вхождений элементов из списка в выводе JSON и сгруппировать их. Ожидаемый результат должен выглядеть следующим образом:

{
   "BMW" :
       {
         "5series" : 3,
         "3series" : 1,
         "7series" : 1,
       },
   "AUDI" :
      {
         "A3" : 1,
         "A7" : 1,          
      },
  "MERCEDES":
      {
         "EClass" : 0,
         "SClass" : 0
     }
}

Мне нужно найти «компанию» из списка элементов. Это будет включать имена, которые могут отсутствовать в ответе JSON иногда, тогда ожидаемый результат должен включать это как 0. Имена «модели» (3,5,7, A3 и c ..,) являются фиксированными, поэтому мы знаем, что это только те, которые могут или не могут быть в ответе json API.

Например: список содержит 3 названия компаний в коде ниже. - companyname = ["BMW," AUDI "," MERCEDES "]. Однако иногда ответ API JSON может не содержать один или несколько элементов. В этом случае отсутствует" MERCEDES ", но окончательный вывод должен включать "MERCEDES", а также со значением 0.

Вот то, что я пробовал до сих пор:

def modelcount():
    companyname= ["BMW","AUDI","MERCEDES"]
    url = apiurl   

    #Send Request

    apiresponse = requests.get(url, auth=(user, password), headers=headers, proxies=proxies)

# Decode the JSON response into a dictionary and use the data
    data = apiresponse.json()

    print(len(data['result']))

    3series= 0
    5series= 0
    7series= 0
    A3=0
    A7=0
    EClass = 0
    SClass = 0
    modelcountjson = {}

    for name in companyname:

        for item in data['result']:
            models= {}
            if item['company'] == name:
                if item['model'] == 3:
                    3series = 3series + 1
                elif item['model'] == 5:
                    5series = 5series + 1
                elif item['model'] == 7:
                    7series = 7series + 1

                models['3series'] = 3series
                models['5series'] = 5series
                models['7series'] = 7series                           

#I still haven't written AUDI, MERCEDES above. This is where i feel i am writing inefficiently.

                   modelcountjson[name] = models

    return jsonify(modelcountjson)


```

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

Большое спасибо за вашу помощь.

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Полезный пакет для непосредственной работы со словарями и списками в стиле JSON - toolz (подробности см. В документации ). Таким образом, вы можете кратко сгруппировать данные и подсчитать число экземпляров каждой модели, обрабатывая при этом потенциально отсутствующие данные отдельно:

from toolz import itertoolz

result = {
   "result": [
       {
         "company" : "BMW",
         "model" : "5"
       },
       {
         "company" : "BMW",
         "model" : "5"
       },
       {
         "company" : "BMW",
         "model" : "5"
       },
       {
         "company" : "BMW",
         "model" : "3"
       },
       {
         "company" : "BMW",
         "model" : "7"
       },
       {
         "company" : "AUDI",
         "model" : "A3"
       },
       {
         "company" : "AUDI",
         "model" : "A7"
       },
    ]
}

final_output = {}
grouped_result = itertoolz.groupby('company', result['result'])

if 'MERCEDES' not in grouped_result:
    final_output['MERCEDES'] = {
        'EClass': 0,
        'SClass': 0
    }

for key, value in grouped_result.items():
    models = itertoolz.pluck('model', value)
    final_output[key] = itertoolz.frequencies(models) 

В результате получается:

{'AUDI': {'A3': 1, 'A7': 1}, 'BMW': {'3': 1, '5': 3, '7': 1}, 'MERCEDES': {'EClass': 0, 'SClass': 0}}
0 голосов
/ 15 марта 2020

Вы можете go немного разделить код и конфигурацию:

conf = {
    'BMW': {'format': '{}series', 'keys': ['3', '5', '7']},
    'AUDI': {'format': '{}', 'keys': ['A3', 'A7']},
    'MERCEDES': {'format': '{}Class', 'keys': ['E', 'S']},
}

def modelcount():
    # retrieve `data`
    # ...
    result = {
        k: {
            v['format'].format(key): 0 for key in v['keys']
        } for k, v in conf.items()
    }
    for car in data['result']:
        com = car['company']
        mod = car['model']
        key = conf[com]['format'].format(mod)
        result[com][key] += 1
    for com in result:
        result[com]['Total'] = sum(result[com].values())
    return result

>>> modelcount()
{'BMW': {'3series': 1, '5series': 3, '7series': 1}, 
 'AUDI': {'A3': 1, 'A7': 1}, 
 'MERCEDES': {'EClass': 0, 'SClass': 0}}

Таким образом, для большего количества компаний и моделей вам нужно будет только коснуться conf, а не код. Сложность по времени составляет O(m+n) с m общим количеством отдельных моделей и n количеством автомобилей в ответе API.

...