R (4.6) Module 5
Pipes, functionals and iteration interview questions
Interview questions on pipes, functionals and iteration: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher to mid
What does the native pipe |> do in R?
Answered in the lesson The native pipe |> and anonymous functions
-
Fresher to mid
What is the difference between lapply(), sapply() and vapply()?
Answered in the lesson The apply family and base functionals
-
Fresher to mid
What does map_dbl() promise that map() does not?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
Your team wants to replace every %>% in a 3,000-line analysis with the native |>, using find and replace. Which lines will break, which could change their results without an error, how do you find both before running the analysis, and how do you show that the results did not change?
- What it tests
- Knowing where the two pipes follow different rules, using the parser to find problems without running code, and proving that outputs stayed the same.
- First step
- Let the parser find the loud cases first: after the replace, parse every file without running it. Bare function names and braces after the pipe fail at once, with the file, line and column. Then list every use of the dot, because the native pipe treats it as an ordinary name.
- Follow-ups
-
- What do you do with a step written as %>% { . * 2 }?
- Can a result change without any error or warning?
- How do you keep %>% from coming back into the code?
From the lesson The native pipe |> and anonymous functions
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A function in your team's package pipes data into lm() and returns the slope of the model. The package promises to work on R 4.1.2. Which forms of the native pipe may the function use, how do you write its two steps for that version, and how do you keep a later edit from breaking the promise?
- What it tests
- Knowing which release added each piece of the pipe syntax, writing the same steps without the placeholder, and testing on the oldest supported version instead of trusting memory.
- First step
- Date each piece of syntax the function uses: the pipe and the \(x) shorthand came in R 4.1.0, the placeholder for a named argument in 4.2.0, and the placeholder at the head of an extraction in 4.3.0. On 4.1.2 neither use of _ parses, so both steps need another form.
- Follow-ups
-
- Why does the failure show up when the package is installed, not when the function is called?
- Is naming the first argument, lm(formula = y ~ x), a safe replacement?
- When is it right to raise the minimum version instead?
From the lesson The native pipe |> and anonymous functions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A helper returns sapply(files, \(f) nrow(read.csv(f))), and its caller adds the counts with sum(). It passed every test, then one night with no new files the job stopped with "invalid 'type' (list) of argument". Explain what happened, fix the helper, and say which tests would have caught it.
- What it tests
- Knowing how sapply() simplifies and what it returns for empty input, choosing vapply() with the right template, and testing the empty and unusual cases rather than the typical one.
- First step
- Call the helper with no files and look at class() of the result. sapply() returns an empty list when there is nothing to apply over, because it has no result to learn a type from, and sum() cannot add a list. On every earlier night each file gave one count, so the result was a vector.
- Follow-ups
-
- Why did no test fail before?
- What should the helper return when there are no files?
- Is unlist(lapply(...)) an acceptable fix?
From the lesson The apply family and base functionals
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A study joins 12 visit tables with Reduce(\(x, y) merge(x, y, by = "patient"), visits). 480 patients are enrolled, but the joined table has 431 rows, and nothing warned. How do you find where the rows went, decide what the table should contain, and make the join report losses next time?
- What it tests
- Knowing that merge() is an inner join by default, using accumulate = TRUE to see every step of a fold, choosing the kind of join on purpose, and checking keys and row counts.
- First step
- Keep every step of the fold with accumulate = TRUE and print nrow() of each intermediate table. The step where the count falls names the table that lacks those patients, because merge() keeps only the keys found in both of its tables, and the fold applies that rule eleven times.
- Follow-ups
-
- Should the joined table have 480 rows?
- What changes with all.x = TRUE?
- What would you check about the keys before joining?
From the lesson The apply family and base functionals
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A nightly job reads 300 CSV exports with map(files, read_one) and stops when one file is malformed, so the other 299 are lost for the night. Restructure it so the good files are processed, each failure is reported with its file name, and the scheduler still learns that something went wrong.
- What it tests
- Keeping failures as values with safely(), combining the good results once, reporting what failed, and choosing the job's exit status deliberately instead of hiding errors.
- First step
- Separate reading from deciding: map over the files with safely(read_one), so every file gives a result or an error and the loop always finishes. Then split the attempts into the good tables and the failures, before deciding what the job reports.
- Follow-ups
-
- Why not wrap the whole map() in tryCatch()?
- When should one bad file still stop the whole job?
- How do you test the failure path?
From the lesson Iteration with purrr
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
After an update to purrr 1.2, a report that ran for years stops with "Can't coerce from a number to a string" in a call to map_chr(). What changed, how do you fix the call, and how do you find every other call with the same problem before it fails?
- What it tests
- Reading purrr's news for the release, fixing a conversion explicitly, and searching code systematically for calls whose behaviour changed.
- First step
- Read the error's index and name, then purrr's news for 1.2.0: map_chr() no longer converts logical, integer or double results to strings. The function given to map_chr() returns a number, which earlier releases converted for you, from 1.0.0 on with a deprecation warning.
- Follow-ups
-
- Is as.character() always the right fix?
- How could the deprecation warnings have been seen before the update?
- How do you stop an update from surprising the report again?
From the lesson Iteration with purrr
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes