1

I have some duplication of code due to having to do some grouping on 3 different fields in a case class and then populate a new case class with those. Since they share a common schema it should be possible for me to do a function that can take the input of the 3 different fields and populate accordingly. However, I am not exactly sure how to do this.

Schemas:

case class Transaction(
  senderBank: Bank,
  receiverBank: Bank,
  intermediaryBank: Bank)

case class Bank(
  name: String,
  country: Option[String],
  countryCode: Option[String])

case class GroupedBank(
  name: String,
  country: Option[String],
  countryCode: Option[String],
  bankType: String)

Current function I tried to do:

def groupedBank(transactionSeq: Seq[Transaction], bankName: Bank, bankTypeString: String): Iterable[Seq[GroupedBank]] = {
 transactionSeq.groupBy(_ => bankName.name).map {
  case (key, transactionSeq) =>
    val bankGroupedSeq = transactionSeq.map(_ => {
      GroupedBank(
        name = bankName.name,
        country = bankName.country,
        countryCode = bankName.countryCode,
        bankType = bankTypeString)
    })
    bankGroupedSeq
  }
}

I need to do the grouping for SenderBank, receiverBank, and intermediaryBank. However, I am not sure how to refer to them correctly in the function parameter bankName. So for SenderBank I would want to do something like Transaction.senderBank, which would point to the correct fields for name, country and so on for senderBank. For receiverBank it should be similar, so Transactions.receiverBank, which then refers to the correct fields for receiverBank and so on. And again for intermediaryBank the same logic. My question is therefore how can I accomplish something like this or is there another way that would be more appropriate?

3
  • Sorry, it's not clear what you're doing. Do you want transactionSeq.groupBy(_.senderBank.name), transactionSeq.groupBy(_.receiverBank.name), transactionSeq.groupBy(_.intermediaryBank.name)? Commented Nov 20, 2019 at 9:43
  • @DmytroMitin, yes exactly. Sorry that I was a bit unclear. Commented Nov 20, 2019 at 9:48
  • @DmytroMitin, but how would this look like in the function? Commented Nov 20, 2019 at 10:05

1 Answer 1

2

You can pass a function to extract the bank with the correct type from a transaction:

def groupedBank(
  transactionSeq: Seq[Transaction], 
  getBank: Transaction => Bank, 
  bankTypeString: String
): Iterable[Seq[GroupedBank]] = {
  transactionSeq.groupBy(getBank(_).name).map {
    case (key, transactionSeq) =>
      transactionSeq.map { transaction =>
        val bank = getBank(transaction)
        GroupedBank(
          name = bank.name,
          country = bank.country,
          countryCode = bank.countryCode,
          bankType = bankTypeString)
      }
  }
}

And then call it like this:

groupedBank(transactionSeq, _.senderBank, "sender")

It could also be a good idea to abstract the bank type concept into a separate trait:

sealed trait BankGroup {
  def name: String
  def getBank(transaction: Transaction): Bank

  def groupBanks(transactionSeq: Seq[Transaction]): Iterable[Seq[GroupedBank]] = {
    transactionSeq.groupBy(getBank(_).name).map {
      case (key, transactionSeq) =>
        transactionSeq.map { transaction =>
          val bank = getBank(transaction)
          GroupedBank(
            name = bank.name,
            country = bank.country,
            countryCode = bank.countryCode,
            bankType = name)
        }
    }
  }
}

object BankGroup {
  object Sender extends BankGroup {
    def name: String = "sender"
    def getBank(transaction: Transaction): Bank = transaction.senderBank
  }

  object Receiver extends BankGroup {
    def name: String = "receiver"
    def getBank(transaction: Transaction): Bank = transaction.receiverBank
  }

  object Intermediary extends BankGroup {
    def name: String = "intermediary"
    def getBank(transaction: Transaction): Bank = transaction.intermediaryBank
  }

  val values: Seq[BankGroup] = Seq(Sender, Receiver, Intermediary)
  def byName(name: String): BankGroup = values.find(_.name == name)
    .getOrElse(sys.error(s"unknown bank type: $name"))
}

And you can call it in one of those ways:

BankGroup.Sender.groupBanks(transactionSeq)
BankGroup.byName("sender").groupBanks(transactionSeq)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.