A
A
Andrey2019-03-09 22:08:57
go
Andrey, 2019-03-09 22:08:57

Is it possible to write more concise code?

Good evening!
There are streams that periodically send measurements.
The measurements come in this structure:

test data
[
  {
    "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
      }
    ]
  }
]


And it will be handled by the following code:
The code
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

Normal?
All sensors are made as pointers, since the values ​​can be null, both because the stream simply does not have sensors, or because the sensor is not working and this must be distinguished from the fact that the sensor actually sent 0. But not to this code: -)
Thanks in advance.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vladislav, 2019-03-09
@VladimirAndreev

Normal, but there is no limit to perfection)
Missed error checking after `err = json.Unmarshal(raw, &packet)`
also, the code can be simplified if you nest the `RawDataSensorsItems` structure in `ResultRow`
We get:

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"`
}

Because of this, the code inside the loop is simplified:
result = append(
        result,
        ResultRow{
                StreamId: row.StreamId,
                DateTime: row.DateTime,
                RawDataSensorsItems: rowS,
        })
)

also, you can use not a simple `for j := range row.Sensors` by indexes, but immediately with the values ​​`for _, rowS := range row.Sensors` (we ignore the index with `_`, but in `rowS` immediately write the value from the array)
If we rewrite it like this, we get:
for _, row := range packet {
    for _, rowS := range row.Sensors {
        result = append(
                result,
                ResultRow{
                        StreamId: row.StreamId,
                        DateTime: row.DateTime,
                        RawDataSensorsItems: rowS,
                })
    }
}

Full code
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

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question