What this quiz covers
This quiz focuses on Vectorization Vs Loops, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.
A loop constructs running sales totals by assigning the first sale to the first result element and then adding each later sale to the previously computed total.
Which implementation is generally preferred if the complete vector of running totals is required?
sum(sales) because a single vectorized reduction automatically returns every intermediate running total.sales + c(0, sales[-length(sales)]) because adding the previous sale produces the cumulative totals.cumsum(sales) because it is a specialized vectorized operation implementing the required cumulative dependency.R Programming Quiz
Practice Vectorization Vs Loops in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.
This quiz focuses on Vectorization Vs Loops, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.
Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.
A loop constructs running sales totals by assigning the first sale to the first result element and then adding each later sale to the previously computed total.
Which implementation is generally preferred if the complete vector of running totals is required?
sum(sales) because a single vectorized reduction automatically returns every intermediate running total.sales + c(0, sales[-length(sales)]) because adding the previous sale produces the cumulative totals.cumsum(sales) because it is a specialized vectorized operation implementing the required cumulative dependency. (correct answer)cumsum() is R's purpose-built function for computing running totals. Given sales = c(10, 20, 30), it returns c(10, 30, 60) — exactly the vector of intermediate totals the passage describes. It is vectorized, meaning R executes it in optimized compiled code rather than interpreted R loops, making it both faster and cleaner than a manual loop. This makes C the correct and preferred choice.
A is wrong because sum(sales) performs a reduction — it collapses the entire vector into a single scalar (the grand total), discarding every intermediate value. It returns nothing resembling a running total vector.
B contains a plausible-looking formula, but it is mathematically incorrect. Adding each sale to the immediately preceding sale (not the accumulated total) does not produce cumulative sums. For c(10, 20, 30), it yields c(10, 30, 50) instead of c(10, 30, 60) — off as soon as more than two elements exist.
D represents a common misconception: that cumulative dependency automatically requires a loop. R's cumsum() proves this false — specialized vectorized functions can encode sequential logic internally.
As a study tip, remember that R has a family of cumulative functions — cumsum(), cumprod(), cummax(), cummin() — and exam questions will test whether you recognize them as superior alternatives to explicit loops.A script must submit files to a service one at a time. After each submission, it records the returned identifier, waits if the service requests a delay, and may retry that same file before continuing. The service offers no bulk-submission endpoint.
Which approach best fits this task?
Vectorize() because this converts ordered side effects into one bulk service request.vapply() because it guarantees that all submissions occur simultaneously while preserving their input order.Vectorize() actually does. It doesn't batch calls into a single request — it's a wrapper that applies a scalar function element-by-element, essentially building a loop for you. It also gives you no mechanism to inspect intermediate results, handle retries, or introduce conditional delays between calls.
Choice B contains two false claims about vapply(). First, vapply() does not run submissions simultaneously — R is single-threaded by default and vapply() processes elements sequentially. Second, even if parallelism were involved, that would be exactly wrong for a service requiring one-at-a-time submissions with response-dependent behavior.
Choice C is simply false. Passing a vector to a function does not automatically "distribute" it into multiple service calls; the function receives the entire vector as one argument unless it's explicitly written to loop internally.
As a study tip: whenever a question describes side effects that depend on prior outcomes (retries, waits, conditional branching), an explicit loop is almost always the answer over functional-style apply tools.A vector value contains observations, and an integer vector group of the same length identifies each observation's group. Every entry of group is a valid position in the shorter vector threshold. A loop currently assigns flag[i] <- value[i] > threshold[group[i]].
Which expression correctly replaces the loop without relying on unintended recycling?
value > threshold because recycling the threshold vector follows the group labels automatically.threshold > value[group] because indexing the observations applies each group's threshold in order.value[group] > threshold because group indexing aligns the observations with the shorter threshold vector.value > threshold[group] because indexing expands the appropriate threshold to each observation's position. (correct answer)i, compare value[i] to threshold[group[i]]. Notice that group[i] is used to index into threshold, not into value. So the vectorized form needs to expand threshold according to the group vector.
D is correct because threshold[group] uses the group vector as an index, pulling the appropriate threshold for each observation in one shot. The result is a vector the same length as value and group, with each element being the threshold corresponding to that observation's group — exactly mirroring threshold[group[i]] across all i.
A is wrong because value > threshold relies on R's recycling rules, which repeat threshold in order (1, 2, 3, 1, 2, 3, ...) regardless of what group contains. This only works correctly if groups happen to be perfectly sequential, which is not guaranteed.
B reverses the comparison entirely — threshold > value[group] both flips the inequality and indexes value with group, which doesn't match the loop's logic on either count.
C makes a symmetric mistake: it indexes value with group (value[group]) instead of indexing threshold with group. This reorders the observations rather than selecting the correct thresholds, producing a misaligned comparison.
A useful pattern to remember: when a loop uses shortVector[indexVector[i]], the vectorized equivalent is shortVector[indexVector] — index the shorter structure, not the longer one.For each period, an account balance must be updated by applying that period's interest rate to the previously computed balance and then subtracting that period's withdrawal. Both rates and withdrawals vary by period, and every intermediate balance is needed.
Which implementation strategy is most appropriate in base R when no specialized financial function is being used?
initial_balance * cumprod(1 + rate) - cumsum(withdrawal) because compounding and withdrawals can be accumulated independently and then combined.initial_balance + cumsum(initial_balance * rate - withdrawal) because each period's interest is determined by the fixed starting balance.initial_balance * (1 + rate) - withdrawal because elementwise arithmetic automatically carries each period's ending balance into the next period.cumprod and cumsum sound like they handle compounding and withdrawals. But the formula only works when there are no withdrawals reducing the base before the next period's interest is applied. Once withdrawals occur mid-sequence, the two components cannot be accumulated independently — the withdrawal in period 1 changes the base that gets compounded in period 2, breaking the separation.
C incorrectly assumes interest is always earned on the initial balance. In reality, interest compounds on the running balance, which shrinks after each withdrawal.
D mistakes elementwise vector arithmetic for sequential updating. R applies initial_balance * (1 + rate) - withdrawal to the original scalar across all periods simultaneously — it doesn't "carry forward" any computed balance.
Study tip: Whenever you see a recurrence relation where step t explicitly depends on step t−1's output, that's your signal that a loop is necessary — no vectorized shortcut preserves that dependency.A programmer needs log(x) for positive, nonmissing elements of x and NA_real_ everywhere else. Using ifelse(x > 0, log(x), NA_real_) produces the desired final positions but also generates warnings because log(x) is evaluated for invalid elements.
Which replacement best retains vectorized processing while avoiding evaluation of log() at invalid positions?
suppressWarnings(ifelse(x > 0, log(x), NA_real_)) so invalid logarithms are still computed but hidden.NA_real_ result, form a valid-position logical index, and assign log(x[valid]) only at those positions. (correct answer)log(x[x > 0]) because dropping invalid elements preserves both the original length and positional alignment.log() conditionally because logical indexing is not a vectorized operation.ifelse() looks conditional, but it fully evaluates both the true and false expressions across the entire vector before selecting results — meaning log(x) runs on negative and zero elements regardless, triggering warnings.
The cleanest solution is B: preallocate a vector of NA_real_ with the same length as x, compute a logical index valid <- x > 0, then assign result[valid] <- log(x[valid]). This is genuinely vectorized — log() receives a contiguous numeric vector of only valid values in a single call — and it never touches invalid positions. Positional alignment is preserved because you're assigning back into the original index slots.
A is a trap for students who confuse "hiding a problem" with "solving it." suppressWarnings() just silences the output; log() still runs on invalid elements, producing NaN values that could corrupt downstream analysis without any signal.
C looks tempting because log(x[x > 0]) does avoid invalid inputs, but it returns a shorter vector stripped of invalid positions. You lose length and positional alignment entirely — a major problem if you need results to correspond to the original indices of x.
D is simply false. Logical indexing like x[x > 0] is one of R's core vectorized tools, implemented in C under the hood. Replacing it with a loop sacrifices R's performance advantages for no benefit.
As a study tip: whenever you see ifelse() with a function that has a restricted domain, remember that both branches evaluate eagerly — reach for index-and-assign instead.A large numeric matrix m contains some missing values, but every row has at least one observed value. The required output is one mean per row, excluding missing values.
Which implementation is generally preferred for clarity and performance?
mean(m, na.rm = TRUE) because mean() automatically preserves the matrix's row structure and returns one value per row.colMeans(m, na.rm = TRUE) because matrix columns represent the observations within each row.rowMeans(m, na.rm = TRUE) because it is a specialized vectorized function designed for this row reduction. (correct answer)apply(m, 1, mean, na.rm = TRUE) because the general-purpose apply() function handles missing values more reliably than specialized row functions.rowMeans and colMeans) and general-purpose tools (like apply), and knowing when to prefer each is a common exam and real-world concern.
rowMeans(m, na.rm = TRUE) is the correct choice here. It is a built-in vectorized function written in optimized C code specifically to compute one mean per row while excluding NA values. It returns a named numeric vector with exactly one value per row — precisely what the problem requires. This makes C the answer.
Each distractor contains a specific misconception worth understanding. A is flatly wrong: mean(m, na.rm = TRUE) collapses the entire matrix into a single scalar value, completely ignoring row structure. R treats the matrix as one long vector here. B confuses the axis: colMeans() computes one mean per column, not per row — the naming tells you the direction of the output, not the direction of reduction. If you want one value per row, think rowMeans. D is tempting but misleading: apply(m, 1, mean, na.rm = TRUE) does produce correct results, but it is slower and more verbose than rowMeans. The claim that apply handles missing values "more reliably" is false — both handle NA identically when na.rm = TRUE is passed.
A useful study tip: in R, prefer named specialized functions (rowMeans, colMeans, rowSums, colSums) over apply whenever they exist — they're faster, cleaner, and signal intent immediately to anyone reading your code.An expensive deterministic function score() is applied to candidates in priority order. The program needs the position of the first candidate whose score exceeds a limit, and candidates after that position should not be evaluated.
Which approach is most appropriate when early candidates frequently exceed the limit?
score(candidates) for the entire vector and then select the first qualifying position from the complete result.break immediately after the first qualifying score. (correct answer)which.max(score(candidates)) because the largest score necessarily occurs at the first threshold crossing.break (choice B) is the right tool here. You evaluate score() one candidate at a time in priority order, and the instant a score exceeds the limit, you record that position and exit the loop immediately. If early candidates frequently exceed the limit, you may only need to call score() once or twice before stopping — dramatically reducing computation compared to any approach that processes the full vector.
Choice A fails precisely because it ignores the expensive nature of score(). Calling score(candidates) on the entire vector forces R to evaluate every candidate regardless of when the first qualifying one appears. You do far more work than necessary, which the problem explicitly warns you to avoid.
Choice C misunderstands what which.max() does — it finds the position of the largest score, not the first score that crosses a threshold. A candidate with a moderate score that just barely exceeds the limit would be the correct answer, but which.max() would skip it in favor of a higher score elsewhere in the vector.
Choice D introduces a subtle trap: sorting the candidates destroys their original priority order. Even if you then find the first qualifying score after sorting, that position no longer corresponds to the priority ranking the problem requires you to respect.
Your study tip: whenever a question mentions an "expensive" function alongside an ordered stopping condition, that's a signal to reach for a loop with break rather than any vectorized approach that processes everything upfront.A very large vector x must be transformed into squared deviations from its mean. The direct expression (x - mean(x))^2 is fast on smaller data, but on the production machine it fails because the output plus temporary full-length vectors exceed available memory.
Given this measured memory constraint, which response is most appropriate?
out <- c(out, value) inside a loop because repeated concatenation minimizes peak allocation.sapply(x, function(v) (v - mean(x))^2) because sapply() avoids creating intermediate full-length vectors and handles large inputs efficiently.(x - mean(x))^2 is elegant but memory-hungry: R creates a temporary vector for x - mean(x) and another for the squared result, so you briefly hold two or three full-length vectors alongside the original. When x is massive, that multiplication of allocations is exactly what crashes the job. The fix in C — computing mean(x) once, preallocating out <- numeric(length(x)), then filling element-by-element in a loop — keeps only the output vector and the scalar mean alive. Each iteration overwrites a single slot, so peak memory stays near one full-length vector rather than three.
A is a tempting trap because vectorized code is generally faster, but "vectorized" does not mean "memory-minimal." Vectorized operations still create intermediate full-length objects; that's precisely the problem described. B is the worst of all options: growing a vector with c(out, value) inside a loop copies the entire existing vector at each step, causing both quadratic time complexity and escalating memory use — the opposite of what you want. D is doubly flawed: sapply calls mean(x) on the full vector for every single element, an O(n²) disaster in both time and repeated work, and it offers no memory advantage over the direct expression.
For exam questions involving large data and memory limits, always prioritize how many full-length copies a solution creates — that number, not vectorization alone, determines peak allocation.Two numeric vectors x and y are given. The required result is a matrix in which each row corresponds to an element of x, each column corresponds to an element of y, and each entry is the row value minus the column value.
Which implementation is generally preferred when the complete matrix is required?
outer(x, y, FUN = "-") because it directly applies subtraction to every pair of elements. (correct answer)x - y because recycling automatically expands both vectors into the required two-dimensional result.x %o% y because the outer-product operator computes pairwise subtraction when its inputs are numeric.outer(x, y, FUN = "-") is the correct and preferred approach here. It systematically applies the subtraction function to every (x_i, y_j) pair, returning a matrix with length(x) rows and length(y) columns, exactly matching the described requirement. It's readable, general-purpose, and efficient — making A the right answer.
B is false and represents a common misconception. Nested loops can solve this problem, but they are slower and more verbose than vectorized alternatives. The claim that "operations involving two indices cannot be expressed by vectorized base R functions" is simply wrong — outer() exists precisely for this purpose.
C is a classic recycling trap. x - y does trigger R's recycling rules, but recycling operates within a single vector dimension, not across two dimensions. The result is a vector, not a matrix, and the recycling pattern may not correspond to the intended pairwise subtraction at all.
D misrepresents the %o% operator. x %o% y is equivalent to outer(x, y, FUN = "*") — it computes pairwise multiplication, not subtraction. Using it here would produce the wrong values entirely.
As a study tip: whenever a question asks about applying an operation to every combination of two vectors in R, outer() with a custom FUN argument should be your first instinct.A programmer standardizes a numeric vector x using scalar values mu and sigma. The current code preallocates z, loops over seq_along(x), assigns (x[i] - mu) / sigma for nonmissing elements, and assigns NA_real_ otherwise. Assume sigma is nonzero.
Which assessment of replacing the loop with z <- (x - mu) / sigma is most accurate?
is.na() condition.mu from a vector invokes recycling that changes the intended calculation.NA) the same way?
R's vectorized arithmetic applies scalar operations elementwise automatically. Writing (x - mu) / sigma subtracts mu from every element of x and divides by sigma — exactly what the loop does one index at a time. Crucially, R propagates NA values through arithmetic operations by design: any calculation involving NA returns NA. So if x[i] is NA, then x[i] - mu is NA, and NA / sigma is NA. The vectorized expression preserves missing positions without any explicit is.na() check, making B correct.
A is wrong because it assumes vectorized arithmetic silently drops or mishandles NA values. In reality, NA propagation is a core feature of R's arithmetic — no special guarding is needed.
C is wrong because subtracting a scalar from a vector is standard, intentional recycling in R. The scalar mu is reused for each element, which is exactly the desired behavior — not a distortion of the calculation.
D is wrong because it prescribes unnecessary extra work. Removing NAs, computing, and reinserting them would be cumbersome and error-prone, and it's completely unnecessary since propagation handles it automatically.
A useful mental rule: in R, if an operation works correctly for one element, vectorization makes it work correctly for all elements — including missing ones — without modification.