Объединение записей словаря Python (считывается из JSON) в зависимости от значений ключей и корректировка значений оставшихся ключей - PullRequest
0 голосов
/ 15 февраля 2020

Я создаю JSON файл из веб-сервиса, которым я не могу управлять, и результат примерно такой:

{
      "steps": [
        {
          "start_station": "TOYOCHO",
          "end_station": "NIHOMBASHI",
          "start_time": 1598317440.0,
          "end_time": 1598317920.0,
          "duration": 8,
          "train_name": "Tokyo Metro Tozai Line Rapid\u00a0for\u00a0NAKANO",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        },
        {
          "start_station": "NIHOMBASHI",
          "end_station": "OSHIAGE",
          "start_time": 1598318340.0,
          "end_time": 1598319000.0,
          "duration": 11,
          "train_name": "Toei Subway Asakusa Line\u00a0for\u00a0NARITA AIRPORT TERMINAL 1",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        },
        {
          "start_station": "OSHIAGE",
          "end_station": "AOTO",
          "start_time": 1598319120.0,
          "end_time": 1598319420.0,
          "duration": 5,
          "train_name": "Line name change, train goes through",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        },
        {
          "start_station": "AOTO",
          "end_station": "KEISEI-TAKASAGO",
          "start_time": 1598319480.0,
          "end_time": 1598319600.0,
          "duration": 2,
          "train_name": "Line name change, train goes through",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        },
        {
          "start_station": "KEISEI-TAKASAGO",
          "end_station": "SHIBAMATA",
          "start_time": 1598320080.0,
          "end_time": 1598320260.0,
          "duration": 3,
          "train_name": "Keisei Kanamachi Line\u00a0for\u00a0KEISEI-KANAMACHI",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        }

Теперь я читаю это как словарь с simplejson и мне нужно удалить все шаги, где train_name означает «Смена названия линии, поезд проходит», но мне нужно учитывать тот факт, что они существуют.

Другими словами:

  1. Из окончательного результата не следует удалять записи "поезд проходит";
  2. Первая запись после"поезд проходит", должен иметь "start_station" поле изменено на предыдущую «конечную станцию» предыдущей записи «поезд проходит через».
  3. «конечная станция» до запись «поезд проходит» должна быть записана как « start_station "первой следующей не-" поезд проходит через "запись.
  4. Сделайте то же самое для" start_time "," end_time "

IOW, если я выведу измененный JSON, это то, что я должен ожидать:

{
      "steps": [
        {
          "start_station": "TOYOCHO",
          "end_station": "NIHOMBASHI",
          "start_time": 1598317440.0,
          "end_time": 1598317920.0,
          "duration": 8,
          "train_name": "Tokyo Metro Tozai Line Rapid\u00a0for\u00a0NAKANO",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        },
        {
          "start_station": "NIHOMBASHI",
          "end_station": "KEISEI-TAKASAGO",
          "start_time": 1598318340.0,
          "end_time": 1598319600.0,
          "duration": 11, # Will get recalculated
          "train_name": "Toei Subway Asakusa Line\u00a0for\u00a0NARITA AIRPORT TERMINAL 1",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null,
        }
        {
          "start_station": "KEISEI-TAKASAGO",
          "end_station": "SHIBAMATA",
          "start_time": 1598320080.0,
          "end_time": 1598320260.0,
          "duration": 3,
          "train_name": "Keisei Kanamachi Line\u00a0for\u00a0KEISEI-KANAMACHI",
          "is_transfer": false,
          "start_track_number": null,
          "end_track_number": null
        }

Число "идет четверть ough "может быть чем угодно, поэтому я не могу ожидать конкретную c длину.

В настоящее время я повторяю запись за записью, так как мне нужно выполнить некоторую обработку:

import simplejson as json

with open("results.json", "r") as handle:
    data = json.load(handle)

for step in data["steps"]:
    # Process stuff

Поэтому я застрял, потому что заблудился, пытаясь отследить предыдущее " не go через "запись.

Есть ли нехакерское решение? Обратите внимание, что я также избегаю перебора словаря, если это необходимо. Чего я не могу сделать, так это изменить данные (я могу добавить поле к JSON, говоря, что это "go through", но не более того).

Также извиняюсь за, возможно, плохо сформулированный заголовок, но трудно описать в нескольких словах, что я имею в виду.

Ответы [ 2 ]

0 голосов
/ 16 февраля 2020

Это то, что сработало для меня: я не отмечаю на принятом, потому что я уверен, что есть лучшие способы сделать это. В итоге я использовал peekable from more_itertools для проверки следующей записи. Я также добавил поле go_through в JSON (что я могу сделать), чтобы указать, какие записи должны быть объединены.

Поэтому я применил следующую логику c:

  1. Если текущая запись не является записью "go through", а следующая запись также не выполняется, обработайте ее обычно
  2. Если текущая запись не является "go through", но следующий - сохранить важные биты (самое важное - начало и время) и пропустить оставшуюся часть обработки
  3. Если текущая запись является "go through", но следующая запись - нет, запишите конечное место и время и объедините их из ранее сохраненной записи, чтобы создать «объединенную» запись.
  4. Если текущая и следующая записи являются «go through» (может произойти), ничего не делать и перейти к следующей итерации
import more_itertools as mlt

iter_records = mlt.peekable(record["steps"])
previous_record = None

for record in iter_records:

    # Extract some stuff from the data
    # Unrelated to the actual problem
    parsed = _parse_record(record)
    start_station, start_date, start_time, *rest = parsed
    end_station, end_date, end_time, *rest = rest
    train_type, train_number = rest
    # Doesn't raise StopIteration with a default value set
    next_record = iter_records.peek(None) 

    if next_record is not None:

        if not record["go_through"] and next_record["go_through"]:
            # Next one is going through: set the start,
            # but don't add anything
            previous_record = record
            continue
        elif not next_record["go_through"] and record["go_through"]:
            # The next one is a "real" one, set the end, and
            # use the previous non-go-through record to extract the data
            parsed = _parse_record(previous_record)
            start_station, start_date, start_time, *_ = parsed
            *_, train_type, train_number = parsed
            previous_record = None
        elif record["go_through"] and next_record["go_through"]:
            # Nothing useful, skip processing
            continue
        # More processing....
0 голосов
/ 15 февраля 2020

Вот мое мнение о том, что вы ищете:

  1. Как мне обработать эти данные?
  2. Учитывая, что вы делаете веб-запрос, я думаю, что результаты могут быть массивными и даже разбиты на страницы. Я советую вам разобраться с № 1, а затем работать с № 2.

Для № 1, один из способов подойти к этому:

# Process data loop
# I will call the "line name change" the "LNC".
new_steps = []

for step in steps:
    start_station = None
    end_station = None
    last_step = None # represents the last step that is
    if is_lnc(step):
        pass # do nothing. that means we don't include it into new_steps
    else:
        if not start_station:
            start_station = step['start_station']
        else:
            step['start_station'] = start_station
            last_step['end_station'] = step['end_station'] # What about appending this? Well, it's referring to what you've already appended so the data is shared.
        new_steps.append(step)
        last_step = step

Этот код не идеален, имеет отсутствующие переменные / функции и может быть неправильным. Но это может помочь вам начать.

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