Reputation: 15
So I got a function in each of my classes which does the same but with diffrent objects in the list, for example I got the methode for Streets and HouseNumbers.
Here the example of the two nearly identical functions, first for Streets:
fun batchInsert(import: List<ImportStreet>, source: String) {
var part : MutableList<ImportStreet> = mutableListOf()
for(i in import)
{
part.add(i)
if(part.size % 25000 == 0)
{
batchUpdate(part, source)
part = mutableListOf()
}
}
if (part.size < 25000) {
batchUpdate(part, source)
}
}
Nearly the same but now for HouseNumbers:
fun batchInsert(import: List<ImportHouseNumber>, source: String) {
var part : MutableList<ImportHouseNumber> = mutableListOf()
for(i in import)
{
part.add(i)
if(part.size % 25000 == 0)
{
batchUpdate(part, source)
part = mutableListOf()
}
}
if (part.size < 25000) {
batchUpdate(part, source)
}
}
Is there a easy or efficent way to get rid of the duplicate code?
Upvotes: 0
Views: 77
Reputation: 2964
Using Kotlin Generics - generic functions, we can create a single function that will work with both of your classes. Any class actually, as long as we are not looking to access class specific functions.
fun <T> batchInsert(import: List<T>, source: String) {
var part: MutableList<T> = mutableListOf()
for (i in import) {
part.add(i)
if (part.size % 25000 == 0) {
batchUpdate(part, source)
part = mutableListOf()
}
}
if (part.size < 25000) {
batchUpdate(part, source)
}
}
I don't know what your batchUpdate
fun does, or how it does it, but it can similarly be changed in the same manner:
fun <T> batchUpdate(batch: List<T>, source: String) {
//I don't know what this function does
}
We could also take advantage of Kotlin's chunked function and make the whole process a bit more efficient (we don't need to create a new list ourselfs).
fun <T> batchInsert(import: List<T>, source: String) {
import
.chunked(25000)
.forEach { currentBatch ->
batchUpdate(currentBatch, source)
}
}
Another "trick" that we can use would be to make the fun a Kotlin extension function (note it doesn't always make sense to use this, it depends on the rest of the project, I'll recommend that you read the docs from the link)
fun <T> List<T>.batchInsert(source:String){
chunked(25000)
.forEach { currentBatch ->
batchUpdate(currentBatch, source)
}
}
Which can be called like this:
fun main() {
val list = listOf<ImportHouseNumber>() //empty list just to show how the extension works
val secondList = listOf<ImportStreet>() //empty list just to show how the extension works
val source = "source"
list.batchInsert(source)
secondList.batchInsert(source)
}
A quick and dirty solution for the case when batchUpdate
can't be a generic (see comments), would be to still have a generic fun between them that will reroute each class into a different direction. Something like this:
fun <T> batchUpdate(batch: List<T>, source: String) {
val first = batch.firstOrNull() ?: return
when (first) {
is ImportStreet -> { /* do stuff with the batch and source */ }
is ImportHouseNumber -> { /* do stuff with the batch and source */ }
}
}
Note: I'm not a big fan of doing things like this, and it is a code smell. But in some cases it is enough to get through an issue. If anybody else has other ideas please advise.
Upvotes: 2