rdata.tableuser-defined-functionsrowwise

Applying a user-defined function to perform row-wise calculations in a data table in R


I’m trying to use a Currency Converter function (custom function) to convert amounts of each Order in a data table from one specific currency to another. I have two tables:

  1. Orders (dfOrders)
  2. Exchange Rates (dfXRate)

Ultimately, I need to convert all amounts for each order (Price, VAT, and Fees) from the “FromCUR” currency to the “ToCUR” currency associated with each order using the Exchange Rate table by matching the FromCUR field to the “From” field in the Exchange Rate table, and the same for the “ToCUR” with the “To” field to get the “Rate” and the “Action” type. Action will be used in the function to either Multiply or Divide the Amount from the Order by the Rate.

My complete code to re-produce the Function and tables is shown below.

Yet, I could not even manage to convert the Price as a start although I need to convert all amounts for each order. When I run the code, R throws the following error: “Error in switch(rate$Action, Multiply = Amount * rate$Rate, Divide = Amount/rate$Rate, : EXPR must be a length 1 vector”

I’m aware that .SDCols might help here, but not sure how to use it either.

Would be grateful if someone can fix the code or suggest an alternative more efficient one. Thanks.

CurConverter <- function(FromCUR, ToCUR, Amount, exchange_rate_table) {
  # Look up exchange rate from the provided table
  rate <- exchange_rate_table[From == FromCUR & To == ToCUR, .(Rate, Action)]
  
  # if (nrow(rate) == 0) {
  #   warning("Exchange rate not found for the specified currencies. Returning original amount.")
  #   return(Amount)
  # }
  
  result <- switch(rate$Action,
                   Multiply = Amount * rate$Rate,
                   Divide = Amount / rate$Rate,
                   Amount) |>
    as.numeric()

    return(result)
}

# Example data tables
dfOrders <- data.table(
  OrderID=c("A","B","C"),
  FromCUR = c("USD", "AED", "GBP"),
  ToCUR = c("EUR", "USD", "USD"),
  Price = c(100, 200, 150),
  VAT=c(10,20,15),
  Fees=c(1,2,3)
)

dfXRate <- data.table(
  From = c("USD", "AED", "GBP"),
  To = c("EUR", "USD", "USD"),
  Rate = c(1.06, 3.6725, 1.25),
  Action = c("Multiply", "Divide", "Divide")
)

# Merge data tables based on currency columns
merged_df <- merge(dfOrders, dfXRate, by.x = c("FromCUR", "ToCUR"), by.y = c("From", "To"), all.x = TRUE)

# Apply the CurConverter function to each row
merged_df[, ConvertedPrice := CurConverter(FromCUR, ToCUR, Price, dfXRate)]

Solution

  • Here is how I would do it:

    library(data.table)
    
    convertCurrenciesWithSymbol <- function(orders, exchangeRates) {
     
      # Merge orders with exchange rates
      mergedData <- merge(orders, exchangeRates, by.x = c("FromCUR", "ToCUR"), by.y = c("From", "To"), all.x = TRUE)
      
      # currency conversion 
      mergedData[, Converted := fifelse(Action == "Multiply" & ToCUR == "EUR", 
                                        paste0(as.character(round(Price * Rate, 2)), " €"),
                                        fifelse(Action == "Divide" & ToCUR == "USD", 
                                                paste0(as.character(round(Price / Rate, 2)), " $"),
                                                paste0("No Change, Original: ", Price)
                                        )
      )]
      return(mergedData)
    }
    
    convertedOrders <- convertCurrencies(dfOrders, dfXRate)
    
    convertedOrders
    

    With switch

    library(data.table)
    
    convertCurrenciesWithSwitch <- function(orders, exchangeRates) {
      # Merge orders and rates
      mergedData <- merge(orders, exchangeRates, by.x = c("FromCUR", "ToCUR"), by.y = c("From", "To"), all.x = TRUE)
      
      # Define a helper function for conversion
      convertWithSwitch <- function(action, toCurrency, price, rate) {
        caseKey <- paste(action, toCurrency)
        switch(caseKey,
               "Multiply EUR" = paste0(as.character(round(price * rate, 2)), " €"),
               "Divide USD" = paste0(as.character(round(price / rate, 2)), " $"),
               paste0("No Change, Original: ", price))
      }
      
      # Currency conversion
      mergedData[, Converted := mapply(convertWithSwitch, Action, ToCUR, Price, Rate)]
      return(mergedData)
    }
    
    
    convertedOrdersWithSwitch <- convertCurrenciesWithSwitch(dfOrders, dfXRate)
    convertedOrdersWithSwitch
    
       FromCUR ToCUR OrderID Price VAT Fees   Rate   Action Converted
    1:     AED   USD       B   200  20    2 3.6725   Divide   54.46 $
    2:     GBP   USD       C   150  15    3 1.2500   Divide     120 $
    3:     USD   EUR       A   100  10    1 1.0600 Multiply     106 €