Skip to content

Instantly share code, notes, and snippets.

@xpando
Last active July 31, 2023 00:16
Show Gist options
  • Save xpando/2629df53d4da0421d772aa96098f6746 to your computer and use it in GitHub Desktop.
Save xpando/2629df53d4da0421d772aa96098f6746 to your computer and use it in GitHub Desktop.
Kotlin CSV serializer example
{
"Seattle": [
{
"inverter": {
"manufacturer": "Inverter Corp",
"model": "Model 1"
},
"arrays": [
{
"count": 10,
"manufacturer": "Module Corp",
"model": "Model A",
"orientation": {
"tilt": 15.0,
"azimuth": 180.0
},
"monthlySolarAccess": {
"JANUARY": 70.0,
"FEBRUARY": 75.0,
"MARCH": 80.0,
"APRIL": 85.0,
"MAY": 90.0,
"JUNE": 95.0,
"JULY": 100.0,
"AUGUST": 95.0,
"SEPTEMBER": 90.5,
"OCTOBER": 85.0,
"NOVEMBER": 80.0,
"DECEMBER": 75.0
}
},
{
"count": 15,
"manufacturer": "Module Corp",
"model": "Model A",
"orientation": {
"tilt": 12.4,
"azimuth": 90.0
},
"monthlySolarAccess": {
"JANUARY": 60.0,
"FEBRUARY": 65.0,
"MARCH": 60.0,
"APRIL": 65.0,
"MAY": 60.0,
"JUNE": 65.0,
"JULY": 60.0,
"AUGUST": 65.0,
"SEPTEMBER": 60.5,
"OCTOBER": 65.0,
"NOVEMBER": 60.0,
"DECEMBER": 65.0
}
}
]
},
{
"inverter": {
"manufacturer": "Inverter Corp",
"model": "Model 2"
},
"arrays": [
{
"count": 25,
"manufacturer": "Module Corp",
"model": "Model B",
"orientation": {
"tilt": 9.25,
"azimuth": 270.0
},
"monthlySolarAccess": {
"JANUARY": 100.0,
"FEBRUARY": 100.0,
"MARCH": 100.0,
"APRIL": 100.0,
"MAY": 100.0,
"JUNE": 100.0,
"JULY": 100.0,
"AUGUST": 100.0,
"SEPTEMBER": 100.5,
"OCTOBER": 100.0,
"NOVEMBER": 100.0,
"DECEMBER": 100.0
}
}
]
}
],
"Boston": [
{
"inverter": {
"manufacturer": "Inverter Corp",
"model": "Model 3"
},
"arrays": [
{
"count": 13,
"manufacturer": "Module Corp",
"model": "Model B",
"orientation": {
"tilt": 9.25,
"azimuth": 270.0
},
"monthlySolarAccess": {
"JANUARY": 100.0,
"FEBRUARY": 100.0,
"MARCH": 100.0,
"APRIL": 100.0,
"MAY": 100.0,
"JUNE": 100.0,
"JULY": 100.0,
"AUGUST": 100.0,
"SEPTEMBER": 100.5,
"OCTOBER": 100.0,
"NOVEMBER": 100.0,
"DECEMBER": 100.0
}
}
]
}
]
}
import com.google.gson.GsonBuilder
import java.time.Month
val csvData = arrayOf(
arrayOf(
"Site_id",
"inverter_id",
"inverter_manufacturer",
"inverter_model",
"module_manufacturer",
"module_model",
"module_count",
"tilt",
"azimuth",
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec"
),
arrayOf(
"Seattle",
"1",
"Inverter Corp",
"Model 1",
"Module Corp",
"Model A",
"10",
"15.0",
"180.0",
"70.0",
"75.0",
"80.0",
"85",
"90",
"95",
"100",
"95",
"90.5",
"85",
"80",
"75"
),
arrayOf(
"Seattle",
"1",
"Inverter Corp",
"Model 1",
"Module Corp",
"Model A",
"15",
"12.4",
"90.0",
"60.0",
"65.0",
"60.0",
"65",
"60",
"65",
"60",
"65",
"60.5",
"65",
"60",
"65"
),
arrayOf(
"Seattle",
"2",
"Inverter Corp",
"Model 2",
"Module Corp",
"Model B",
"25",
"9.25",
"270.0",
"100.0",
"100.0",
"100.0",
"100",
"100",
"100",
"100",
"100",
"100.5",
"100",
"100",
"100"
),
arrayOf(
"Boston",
"1",
"Inverter Corp",
"Model 3",
"Module Corp",
"Model B",
"13",
"9.25",
"270.0",
"100.0",
"100.0",
"100.0",
"100",
"100",
"100",
"100",
"100",
"100.5",
"100",
"100",
"100"
),
)
data class SolarSystem(val inverter: Inverter, val arrays: MutableList<ModuleArray>)
data class Inverter(val manufacturer: String, val model: String)
data class ModuleArray(
val count: Int,
val manufacturer: String,
val model: String,
val orientation: Orientation,
val monthlySolarAccess: Map<Month, Double>
)
data class Orientation(val tilt: Double, val azimuth: Double)
const val SITE_ID = 0
const val INVERTER_ID = 1
const val INVERTER_MANUFACTURER = 2
const val INVERTER_MODEL = 3
const val MODULE_MANUFACTURER = 4
const val MODULE_MODEL = 5
const val MODULE_COUNT = 6
const val TILT = 7
const val AZIMUTH = 8
fun parseOrientation(line: Array<String>) =
Orientation(
tilt = line[TILT].toDouble(),
azimuth = line[AZIMUTH].toDouble(),
)
fun parseMonthlySolarAccess(line: Array<String>) =
(1..12).associate {
Month.of(it) to line[AZIMUTH + it].toDouble()
}
fun parseModuleArray(line: Array<String>) =
ModuleArray(
count = line[MODULE_COUNT].toInt(),
manufacturer = line[MODULE_MANUFACTURER],
model = line[MODULE_MODEL],
orientation = parseOrientation(line),
monthlySolarAccess = parseMonthlySolarAccess(line)
)
fun parseInverter(line: Array<String>) =
Inverter(
manufacturer = line[INVERTER_MANUFACTURER],
model = line[INVERTER_MODEL],
)
fun parseSolarSystem(lines: List<Array<String>>) =
SolarSystem(
inverter = parseInverter(lines.first()),
arrays = lines.map { parseModuleArray(it) }.toMutableList()
)
fun parseSite(lines: List<Array<String>>) =
lines
.groupBy { it[INVERTER_ID] }
.map { (_, inverterLines) -> parseSolarSystem(inverterLines) }
fun usingFold(): MutableMap<String, MutableList<SolarSystem>> =
csvData.asSequence()
.drop(1)
.fold(mutableMapOf()) { sites, line ->
val systems = sites.getOrPut(line[SITE_ID]) { mutableListOf() }
var system =
systems.firstOrNull() { it.inverter.manufacturer == line[INVERTER_MANUFACTURER] && it.inverter.model == line[INVERTER_MODEL] }
if (system == null) {
system = SolarSystem(
inverter = parseInverter(line),
arrays = mutableListOf(),
)
systems.add(system)
}
system.arrays.add(parseModuleArray(line))
sites
}
fun main() {
val gson = GsonBuilder().setPrettyPrinting().create()
val sites1 = csvData.asSequence().drop(1)
.groupBy { it[SITE_ID] }
.map { (siteId, siteLines) -> siteId to parseSite(siteLines) }
.toMap()
println(gson.toJson(sites1))
val sites2 = usingFold()
println(gson.toJson(sites2))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment