Site icon R-bloggers

R Solution for Excel Puzzles

[This article was first published on Numbers around us - Medium, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Puzzles no. 339–343

Puzzles

Author: ExcelBI

Puzzles:
#339: content file
#340: content file
#341: content file
#342: content file
#343: content file

Lets dive into solutions!
Short disclaimer: This weeks riddles were well designed and I found out that very good but also readable solutions will not have different approaches this time. It would only overcomplicate the code. So let started.

Puzzle #339

Puzzles focused on Fibonacci sequence are frequent guests on our puzzles. This time we are taking regular Fibonacci sequence and have “only” to return nth term of sequence. We did it several times, but today I am adding little twist.

Load libraries and data

library(tidyverse)
library(readxl)
library(memoise)

input = read_excel("Nth Fibonacci Number.xlsx", range = "A1:A10")
test = read_excel("Nth Fibonacci Number.xlsx", range = "B1:B10") %>%janitor::clean_names()

Prepare and run function

What is the twist here? We use one technique that I learned not long time ago — memoization. Function with this feature just storing new results in cache and if find out that such computation was already done, do not make calculation, but take result from cache. In our case for example if we do it without memoization line 9 (with 73rd term) would need 72 recursive additions, while if we do it that way: we would have one read from cache, because fib(68) was already stored in cache, and 5 recursive additions.
It will significantly improve data processing time.

fib <- memoise(function(n) {
  if (n <= 2) {
    return(1)
  } else {
    return(fib(n - 1) + fib(n - 2))
  }
})

result = input %>%
  mutate(fib = map_dbl(input$N, fib)) %>%
  select(fib)

Validation

identical(result$fib, test$answer_expected)
#> [1] TRUE

Puzzle 340

This puzzle is extremely easy when approaching it with tidyverse, but goal for “Excel” solvers where to use newly added functions. So let see how lubridate is doing job for us.

Loading libraries and data

library(tidyverse) # lubridate is loading with tidyverse
library(readxl)

input = read_excel("Date Min Max.xlsx", range = "A1:A20")
test = read_excel("Date Min Max.xlsx", range = "C2:F8")

Transformation

result = input %>%
  mutate(Year = year(Date),
         Half = str_c(semester(Date),"H")) %>%
  group_by(Year, Half) %>%
  summarise(`Min Date` = min(Date),
            `Max Date` = max(Date)) %>%
  ungroup()

Validation

identical(test, result)
#> [1] TRUE

Puzzle 341

We have to sort some things… against all odds. Or maybe not. We have to sort only digits in given numbers that are on odd positions (1,3,5 and so on). Let’s try it out.

Loading libraries and data

library(tidyverse)
library(readxl)

input = read_excel("Sort Alternate.xlsx", range = "A1:A11") %>% janitor::clean_names()
test = read_excel("Sort Alternate.xlsx", range = "B1:B11") %>% janitor::clean_names()

Transforming data

sort_odd_digits = function(number) {
  digits = strsplit(as.character(number), "")[[1]]
  if (length(digits) < 2) {
    return(as.numeric(paste0(digits, collapse = "")))
  }
  odd_digits = digits[seq(1, length(digits), 2)]
  even_digits = digits[seq(2, length(digits), 2)]
  sorted_odd = sort(odd_digits)
  digits[seq(1, length(digits), 2)] = sorted_odd
  number = digits %>% paste0(collapse = "")
  return(number)
}

result  = input %>%
  mutate(answer_expected = map(number_string, sort_odd_digits))
Validation
identical(unlist(result$answer_expected), test$answer_expected)
#> [1] TRUE

Puzzle 342

Tsamina mina, eh, eh
Waka waka, eh, eh
Tsamina mina zangalewa
This time for Africa

I realized that I still remember World Cup in South Africa 2010. And this puzzle take us to South Africa. We have to check some IDs to find out who has illegally forged documents. ID number in South Africa has certain structure which can be checked and confirmed, but it is not that easy. There is an algorithm called Luhn Algorithm used. It is deeply described in puzzle content and on Wikipedia for example so let’s try this challenge.

Load libraries and data

library(tidyverse)
library(readxl)

input = read_excel("South Africa National ID Validation.xlsx", range = "A1:A10") %>% janitor::clean_names()
test  = read_excel("South Africa National ID Validation.xlsx", range = "B1:B4") %>% janitor::clean_names()

Data transformation

validate_id = function(number) {
  digits = strsplit(as.character(number), "")[[1]]
  odd_digits = digits[seq(1, 12, 2)]
  even_digits = digits[seq(2, 12, 2)]
  
  dob = str_sub(number, 1, 6) %>% as.Date(format = "%y%m%d")
  
  A = sum(as.numeric(odd_digits))
  B = str_c(even_digits, collapse = "") %>% as.numeric()
  B2 = B * 2
  C = strsplit(as.character(B2), "")[[1]] %>% as.numeric() %>% sum()
  D = A + C
  Dmod = D %% 10
  Z13 = str_sub(number, 13, 13) %>% as.numeric()
  Z = ifelse(Dmod == 0, 0, 10 - D %% 10)
  
  is_Z_valid = Z == Z13
  is_status_valid = str_sub(number, 11, 11) %>% as.numeric() %>% between(0, 1)
  is_valid_length = length(digits) == 13
  is_date_valid = !is.na(dob)
  final_check = is_Z_valid & is_date_valid & is_valid_length & is_status_valid
  
  return(final_check)
}

result  = input %>%
  mutate(answer_expected = map(sa_i_ds, validate_id)) %>%
  filter(answer_expected == TRUE)identical(result$sa_i_ds, test$answer_expected)

Validation

identical(result$sa_i_ds, test$answer_expected)
#> [1] TRUE

Puzzle 343

Palindromes are all about symetry, and I wonder if giving palindromic puzzle on no. 343 was intentional or just coincidence. Nonetheless we had some numbers given, some of them were already palindromes, some of them not. Our goal was to find nearest palindromic number. What is really interesting if you are looking for nearest palindrome from palindrome itself, there is a chance that you will find two on the same distance.

Load libraries and data

library(tidyverse)
library(readxl)
library(stringi)

input = read_excel("Nearest Palindrome.xlsx", range = "A1:A10") %>% janitor::clean_names()
test  = read_excel("Nearest Palindrome.xlsx", range = "B1:B10") %>% janitor::clean_names()

Data transformation

find_closest_palindromes <- function(number) {
  num_str <- as.character(number)
  len <- nchar(num_str)
  is_odd <- len %% 2 == 1
  half_len <- (len + 1) %/% 2
  
  first_half <- substr(num_str, 1, half_len)stat

  candidates <- map_dbl(c(1, 0, -1), ~ {
    modified_first_half <- as.numeric(first_half) + .x
    modified_first_half_str <- as.character(modified_first_half)
    if (nchar(modified_first_half_str) < half_len) {
      modified_first_half_str <- str_pad(modified_first_half_str, half_len, pad = "0")
    }
    second_half <- substr(modified_first_half_str, 1, half_len - is_odd)
    as.numeric(paste0(modified_first_half_str, stri_reverse(second_half)))
  })
  
  differences <- abs(number - candidates) 
  valid_differences <- differences[differences != 0]
  closest_values <- candidates[differences == min(valid_differences)]
  
  return(paste(closest_values, collapse = ", "))
}

result = input %>%
  mutate(result = map(number, find_closest_palindromes) %>% unlist())

Validation

identical(result$result, test$answer_expected)
#> [1] TRUE

Feel free to comment, share and contact me with advices, questions and your ideas how to improve anything.


R Solution for Excel Puzzles was originally published in Numbers around us on Medium, where people are continuing the conversation by highlighting and responding to this story.

To leave a comment for the author, please follow the link and comment on their blog: Numbers around us - Medium.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Exit mobile version