Search code examples
androidkotlinfold

Fold with Kotlin in a property of a data class model in an Android app


I'm not sure the title is clarifying enough, so I'll explain here: I have four models:

This model is the one I use for parsing the JSON from a file

@JsonClass(generateAdapter = true)
data class Account(
    val account: String,
    val balance: String,
    val transactions: List<Transaction>
)

This Account has a list of Transactions:

@JsonClass(generateAdapter = true)
data class Transaction(
    val id: String,
    val amount: String,
    val description: String,
    val otherAccount: String,
    val date: String
)

For the UI layer, I have some equivalent models:

data class AccountEntity(
    val account: String,
    val balance: String,
    val transactions: List<TransactionEntity>
)

and

data class TransactionEntity(
    var amount: BigDecimal,
    var balanceBefore: BigDecimal,
    var balanceAfter: BigDecimal,
    val description: String,
    val otherAccount: String,
    val date: Date
)

The tricky thing I want to do is, that an Account has a balance and I need to show in every TransactionData the balanceBefore and the balanceAfter which are respectively, the balance of the account BEFORE this transaction was made, and the balance of the account AFTER this transaction was made.

For me this is a bit tricky not only to understand but also to implement. I thought of maybe implementing some sort of fold operation in every transaction, but I'm not sure how to apply it only in the balanceBefore and the balanceAfter properties.

Any other idea? Thanks a lot in advance!


Solution

  • Well, it's some sort of reduce/fold function that also allows you to map your Transaction objects.

    What this function do is to track the current balance in an accumulator and transform each Transaction object:

    inline fun <R> List<Transaction>.map(
        initial: Int,
        transform: (transaction: Transaction, beforeBalance: Int, afterBalance: Int) -> R
    ): List<R> {
        var accumulator = initial
        val destination = ArrayList<R>()
    
        for (transaction in this) {
            val after = accumulator - transaction.amount
            destination.add(transform(transaction, accumulator, after))
            accumulator = after
        }
        return destination
    }
    

    And you can use it like:

    account.transactions.map(account.balance, {t, b, a-> TransactionEntity(...)})
    

    To be more generic and functional, you can move this line accumulator - transaction.amount to the function parameter as a fold input, and call the function foldMap or whatever which reduce your current transaction and also map it.