VladimirAndreev
@VladimirAndreev
php web dev

Можно ли написать более лаконичный код?

Доброго вечера!
Есть потоки, которые периодически присылают измерения.
Измерения приходят в такой структуре:
Тестовые данные
[
  {
    "stream_id": 10,
    "date_time": "2019-03-09 21:38:00+0300",
    "sensors": [
      {
        "a_key": "a",
        "b_key": 1,
        "sensor_a": 10,
        "sensor_b": 14,
        "sensor_c": 21,
        "sensor_d": 16,
        "sensor_e": 15,
        "sensor_f": 20
      },
      {
        "a_key": "a",
        "b_key": 2,
        "sensor_a": 12,
        "sensor_b": 11,
        "sensor_c": 20,
        "sensor_d": 14,
        "sensor_e": 17,
        "sensor_f": 22
      },
      {
        "a_key": "b",
        "b_key": 1,
        "sensor_a": 12,
        "sensor_b": 11,
        "sensor_c": 20,
        "sensor_d": 14,
        "sensor_e": 17,
        "sensor_f": 22
      }
    ]
  },
  {
    "stream_id": 14,
    "date_time": "2019-03-09 21:38:00+0300",
    "sensors": [
      {
        "a_key": "a",
        "b_key": 1,
        "sensor_a": 31,
        "sensor_b": 26,
        "sensor_c": 20,
        "sensor_d": null,
        "sensor_e": null,
        "sensor_f": null
      },
      {
        "a_key": "b",
        "b_key": 1,
        "sensor_a": 40,
        "sensor_b": 22,
        "sensor_c": 31,
        "sensor_d": null,
        "sensor_e": null,
        "sensor_f": null
      }
    ]
  }
]



И это будет обрабатываться следующим кодом:

Код
package main

import (
	"encoding/json"
	"io/ioutil"
)

func main() {

	raw, err := ioutil.ReadFile("./data/raw.json")

	PanicIfErr(err)

	var packet DataPacket
	var result ResultPacket

	err = json.Unmarshal(raw, &packet)

	for i := range packet {

		row := packet[i]

		for j := range row.Sensors {

			rowS := row.Sensors[j]

			result = append(
				result,
				ResultRow{
					StreamId: row.StreamId,
					DateTime: row.DateTime,
					AKey:     rowS.AKey,
					BKey:     rowS.BKey,
					SensorA:  rowS.SensorA,
					SensorB:  rowS.SensorB,
					SensorC:  rowS.SensorC,
					SensorD:  rowS.SensorD,
					SensorE:  rowS.SensorE,
					SensorF:  rowS.SensorF,
				})
		}
	}

	content, err := json.Marshal(result)

	PanicIfErr(err)

	err = ioutil.WriteFile("./data/output.json", content, 0644)

	PanicIfErr(err)
}

func PanicIfErr(err error) {

	if err != nil {

		panic(err)
	}
}

type ResultPacket []ResultRow

type ResultRow struct {
	StreamId int    `json:"stream_id"`
	DateTime string `json:"date_time"`
	AKey     string `json:"a_key"`
	BKey     int    `json:"b_key"`
	SensorA  *int    `json:"sensor_a"`
	SensorB  *int    `json:"sensor_b"`
	SensorC  *int    `json:"sensor_c"`
	SensorD  *int    `json:"sensor_d"`
	SensorE  *int    `json:"sensor_e"`
	SensorF  *int    `json:"sensor_f"`
}

type RawDataSensorsItems struct {
	AKey    string `json:"a_key"`
	BKey    int    `json:"b_key"`
	SensorA *int    `json:"sensor_a"`
	SensorB *int    `json:"sensor_b"`
	SensorC *int    `json:"sensor_c"`
	SensorD *int    `json:"sensor_d"`
	SensorE *int    `json:"sensor_e"`
	SensorF *int    `json:"sensor_f"`
}

type RawDataRow struct {
	StreamId int                   `json:"stream_id"`
	DateTime string                `json:"date_time"`
	Sensors  []RawDataSensorsItems `json:"sensors"`
}

type DataPacket []RawDataRow


Нормалёк?
Все sensors сделаны указателями, так как в значениях может быть null как по тому, что сенсоров у стрима просто нет, так и потому, что сенсор не исправен и это надо отличать от того, что сенсор прислал реально 0. Но уже не этому коду :-)

Заранее спасибо.
  • Вопрос задан
  • 184 просмотра
Решения вопроса 1
@ghostiam
На Go писатель, серверов пинатель.
Нормально, но нет предела совершенству)

Пропущенна проверка на ошибки после `err = json.Unmarshal(raw, &packet)`
так же, код можно упростить, если вложить структуру `RawDataSensorsItems` в `ResultRow`
Получим:
type ResultRow struct {
  StreamId int    `json:"stream_id"`
  DateTime string `json:"date_time"`
  RawDataSensorsItems
}

type RawDataSensorsItems struct {
  AKey    string `json:"a_key"`
  BKey    int    `json:"b_key"`
  SensorA *int    `json:"sensor_a"`
  SensorB *int    `json:"sensor_b"`
  SensorC *int    `json:"sensor_c"`
  SensorD *int    `json:"sensor_d"`
  SensorE *int    `json:"sensor_e"`
  SensorF *int    `json:"sensor_f"`
}


Из за чего упроститься код внутри цикла:
result = append(
        result,
        ResultRow{
                StreamId: row.StreamId,
                DateTime: row.DateTime,
                RawDataSensorsItems: rowS,
        })
)


так же, можно использовать не простой `for j := range row.Sensors` по индексам, а сразу со значениями `for _, rowS := range row.Sensors` (игнорируем с помощью `_` индекс, а в `rowS` сразу записываем значение из массива)
Если так переписать, то получим:
for _, row := range packet {
    for _, rowS := range row.Sensors {
        result = append(
                result,
                ResultRow{
                        StreamId: row.StreamId,
                        DateTime: row.DateTime,
                        RawDataSensorsItems: rowS,
                })
    }
}


Полный код
package main

import (
	"encoding/json"
	"io/ioutil"
)

func main() {
	raw, err := ioutil.ReadFile("./data/raw.json")
	PanicIfErr(err)

	var packet DataPacket
	var result ResultPacket

	err = json.Unmarshal(raw, &packet)
	PanicIfErr(err)

	for _, row := range packet {
		for _, rowS := range row.Sensors {
			result = append(
				result,
				ResultRow{
					StreamId:            row.StreamId,
					DateTime:            row.DateTime,
					RawDataSensorsItems: rowS,
				})
		}
	}

	content, err := json.Marshal(result)
	PanicIfErr(err)

	err = ioutil.WriteFile("./data/output.json", content, 0644)
	PanicIfErr(err)
}

func PanicIfErr(err error) {
	if err != nil {
		panic(err)
	}
}

type ResultPacket []ResultRow

type ResultRow struct {
	StreamId int    `json:"stream_id"`
	DateTime string `json:"date_time"`
	RawDataSensorsItems
}

type RawDataSensorsItems struct {
	AKey    string `json:"a_key"`
	BKey    int    `json:"b_key"`
	SensorA *int   `json:"sensor_a"`
	SensorB *int   `json:"sensor_b"`
	SensorC *int   `json:"sensor_c"`
	SensorD *int   `json:"sensor_d"`
	SensorE *int   `json:"sensor_e"`
	SensorF *int   `json:"sensor_f"`
}

type RawDataRow struct {
	StreamId int                   `json:"stream_id"`
	DateTime string                `json:"date_time"`
	Sensors  []RawDataSensorsItems `json:"sensors"`
}

type DataPacket []RawDataRow
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы