R Programming Quiz: Tibbles
10 questions · exam conditions
0:00
TibblesQuestion 1 of 10

A base data frame with 12 rows is converted using tb <- tibble::as_tibble(base_df) and then entered at the console.

Which statement best describes the converted object and its default display?

tb inherits only from tbl_df, losing its data.frame class, and only the printed rows are retained.
tb inherits from both tbl_df and data.frame, and its console display may abbreviate rows or columns.
tb retains only the data.frame class, so conversion adds no new classes and base printing is used.
tb is restructured into a non-data-frame format, so ordinary row and column subsetting no longer applies.
← Back to quizzes

R Programming Quiz

R Programming Quiz: Tibbles

Practice Tibbles in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.

What this quiz covers

This quiz focuses on Tibbles, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.

How to use this quiz

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.

All questions

Question 1

A base data frame with 12 rows is converted using tb <- tibble::as_tibble(base_df) and then entered at the console.

Which statement best describes the converted object and its default display?

  1. tb inherits only from tbl_df, losing its data.frame class, and only the printed rows are retained.
  2. tb inherits from both tbl_df and data.frame, and its console display may abbreviate rows or columns. (correct answer)
  3. tb retains only the data.frame class, so conversion adds no new classes and base printing is used.
  4. tb is restructured into a non-data-frame format, so ordinary row and column subsetting no longer applies.
Explanation: When working with tibbles in R, the key concept being tested is class inheritance — how as_tibble() modifies an object's class vector and what that means for printing behavior. When you call tibble::as_tibble(base_df), the resulting object carries a class vector of c("tbl_df", "tbl", "data.frame"). This means tb simultaneously is a tibble and is a data frame — it inherits from both. Because of this dual inheritance, tibble's custom print() method activates, which smartly abbreviates output: it shows only as many rows and columns as fit your console, displays data types beneath column names, and summarizes omitted rows/columns. With 12 rows, you'll likely see all of them, but the formatting still follows tibble's rules. This makes B the correct answer. A is wrong on two counts: tb does retain data.frame in its class vector, and no data is dropped — printing is just visual abbreviation, not actual row removal. C gets it exactly backwards; conversion adds new classes (tbl_df and tbl) on top of data.frame, it does not strip them away. Base printing is not used — tibble's method takes precedence via R's S3 dispatch. D is a misconception about tibbles entirely; they remain rectangular data frames under the hood, so standard [, [[, and $ subsetting all work normally. A useful habit: when you see questions about tibbles, immediately think about the full class vector. Running class(tb) on any tibble will show you all three inherited classes, reminding you that tibbles extend data frames rather than replace them.

Question 2

An analyst runs options(tibble.print_max = 4) and then executes x <- tibble::tibble(id = 1:9); y <- print(x) in an interactive R session.

The console displays only part of x. Which statement about y is correct?

  1. y contains four rows because print() returns the displayed subset.
  2. y contains nine rows because print() invisibly returns the original tibble. (correct answer)
  3. y is NULL because print() produces output but returns no object.
  4. The assignment fails because an invisibly returned value cannot be assigned.
Explanation: When working with R's print() function, it's essential to distinguish between what gets displayed and what gets returned. These are two separate behaviors, and tibbles exploit this distinction elegantly. In R, print() always invisibly returns the object it was given — the full, unmodified object. The options(tibble.print_max = 4) setting only controls how many rows the tibble renders to the console; it never truncates the underlying data. So when you run y <- print(x), the console shows a condensed view (4 rows plus a note about remaining rows), but y receives the complete 9-row tibble that print() invisibly returned. That makes B correct. A is wrong because it conflates the display with the return value. print() doesn't slice or filter the object — it simply renders a view of it. The tibble stored in y is identical to x. C is wrong because print() never returns NULL. This is a common misconception about functions with side effects: just because a function's primary job is to produce output doesn't mean it returns nothing. In R, print() consistently returns its first argument. D is wrong because invisible return values are perfectly assignable. "Invisible" only means the value won't auto-print if left unassigned at the top level — it doesn't prevent assignment at all. A useful rule of thumb: in R, print() is always a pass-through — it shows something, then hands the original object back. Printing options affect the view, never the value.

Question 3

A tibble has columns named account, region, revenue, cost, and margin. Because the console is narrow, printing it shows values for only account and region, followed by a message indicating that three additional variables are not displayed.

Which conclusion is justified by this output?

  1. The tibble still has five columns, and the omitted columns remain directly accessible. (correct answer)
  2. The tibble now has two columns because printing dropped the columns that did not fit.
  3. The tibble has five columns, but the omitted columns were converted entirely to missing values.
  4. The tibble has two columns, while the three omitted names are retained only as metadata.
Explanation: Whenever you see a question about how tibbles display data in R, the key distinction to keep in mind is that printing is purely cosmetic — it never modifies the underlying data structure. When a tibble is too wide for the console, R intelligently truncates the printed output and appends a message listing the omitted column names (e.g., # ... with 3 more variables: revenue, cost, margin). This is a display-only behavior. The tibble in memory remains completely intact with all five columns, and you can still access any omitted column directly using $ notation or select() — confirming that A is correct. B is wrong because printing a tibble never drops columns. The tibble does not shrink to two columns just because the console is narrow; R is simply being polite about screen real estate. C is incorrect for a similar reason — no data transformation occurs during printing, so values are not converted to NA. The columns are fully intact, not zeroed out. D is wrong on two counts: the tibble retains all five columns (not two), and the omitted names are not relegated to metadata — they are full, first-class columns you can query at any time. A useful mental model: think of printing a tibble like looking through a window that's too small to show the whole room. The furniture you can't see is still there — the window just isn't wide enough. As a study tip, remember that tibble's smart printing is a feature, not a transformation — it exists to improve readability without ever touching your data.

Question 4

Given tb <- tibble::tibble(a = 1:3, b = 4:6), a programmer runs one <- tb[, "a"] and two <- tb[["a"]].

Which statement correctly compares one and two?

  1. Both objects are integer vectors because selecting a single tibble column always simplifies.
  2. one is an integer vector with values 1, 2, 3, while two is a one-column tibble.
  3. Both objects are one-column tibbles because tibble [ and [[ both preserve the container.
  4. one is a one-column tibble, while two is an integer vector with values 1, 2, 3. (correct answer)
Explanation: When working with tibbles in R, the subsetting operator you choose determines whether you get back a container (a tibble) or the raw contents (a vector). This is one of the most important behavioral differences between [ and [[. Using single brackets tb[, "a"] tells R: "give me a subset of this tibble." Because tibbles are designed to be predictable and non-simplifying, they always return another tibble when you use [, even if only one column is selected. So one is a one-column tibble. Using double brackets tb[["a"]] says: "extract the element named a from this tibble." This drills into the structure and returns the column's underlying data — in this case, an integer vector 1, 2, 3. That makes D correct: one is a one-column tibble and two is an integer vector. A is wrong because [ on a tibble never simplifies to a vector — that drop behavior belongs to base R data frames (with drop = TRUE), not tibbles. B has the two results exactly backwards, confusing which operator preserves structure and which extracts. C is wrong because [[ does not preserve the container; it extracts the contents, returning a plain vector, not a tibble. A useful memory trick: think of [[ as "reach inside and pull it out" (vector), while [ is "slice off a piece while keeping the wrapper" (tibble). On R exams, questions about subsetting tibbles almost always test whether you know this non-simplifying guarantee.

Question 5

A tibble is created with tb <- tibble::tibble(sales total = c(8L, 9L), region = c("E", "W")). The non-syntactic column name is retained exactly as written.

Which expression returns the integer vector c(8L, 9L) rather than a one-column tibble or an error?

  1. tb$\sales total`— backtick-quoting the non-syntactic name in a$` expression (correct answer)
  2. tb[, "sales total"] — single-bracket column selection with a character index
  3. tb$sales.total — using the dot-separated repair of the original name
  4. tb["sales total"] — one-element character index inside single brackets
Explanation: When working with non-syntactic column names in R (names containing spaces, special characters, or starting with numbers), the key question is always: which operator returns an atomic vector versus a tibble, and how does each operator handle unusual names? The $ operator extracts a column as an atomic vector — exactly what the question asks for. To use $ with a non-syntactic name like sales total, you must wrap the name in backticks: tb$`sales total`. This tells the R parser to treat everything inside the backticks as a single name rather than two tokens. That's why A is correct — it returns the integer vector c(8L, 9L) directly. B is a common trap. tb[, "sales total"] looks like it should work, but with a tibble (unlike a base data frame), single-bracket subsetting with a comma still returns a tibble, not a vector. You'd need [[ or $ to extract the raw vector. C fails because tibbles do not silently repair non-syntactic names when you create them — the column is stored as "sales total" with the space intact. There is no sales.total column, so tb$sales.total returns NULL. This dot-substitution is a behavior of data.frame() with check.names = TRUE, not tibbles. D shares the same problem as B: tb["sales total"] uses single brackets without a comma, which also returns a one-column tibble, not a vector. Your study tip: remember that $ and [[ are your "extract to vector" operators, while [ is your "keep it a tibble/data.frame" operator — and always use backticks with $ for non-syntactic names.

Question 6

The object tb is a tibble with 12 rows and five columns. The programmer runs print(tb, n = 3, width = Inf).

How does this call affect the console output and the underlying object?

  1. It permanently changes tb to three rows and displays every remaining column.
  2. It displays all 12 rows and three columns, while tb retains all five columns.
  3. It displays three rows and all five columns, while tb remains a 12-row tibble. (correct answer)
  4. It displays three rows and only columns that fit the current finite console width.
Explanation: When you call print() on a tibble, you're controlling display behavior only — the underlying object in your R environment is never modified. This distinction between printing and mutating is central to how R works, and it's exactly what this question tests. The two arguments here do different things. n = 3 limits the number of rows shown in the console to three, and width = Inf tells R to ignore the console's line-width constraint and display all columns, no matter how many there are. So the output shows 3 rows and all 5 columns — but tb itself still has 12 rows and 5 columns in memory. That makes C the correct answer. A is wrong on two counts: print() never permanently changes a tibble, and width = Inf expands columns rather than removing them. B reverses the roles of the two arguments — it swaps what n and width control, suggesting n = 3 affects columns and width affects rows, which is backwards. D is a tempting distractor because tibbles do truncate columns by default when width is unspecified — but here width = Inf explicitly removes that constraint, so all five columns are shown, not just those fitting a finite console width. A useful mental model: treat print() on a tibble like adjusting a window's zoom — you change what you see, never what's there. On exam questions like this, always ask yourself: "Does this function return a modified object, or just display something?" For tibble printing, it's always the latter.

Question 7

A tibble is defined as tb <- tibble::tibble(customer = c("Ana", "Bo"), custom = c(TRUE, FALSE)). A programmer then evaluates tb$cust.

What is the expected result?

  1. The customer column is returned because it is the first column beginning with cust.
  2. The custom column is returned because it is the shortest name matching the prefix.
  3. A two-column tibble is returned because both column names share the cust prefix.
  4. NULL is returned with a warning because tibble $ requires an exact column name. (correct answer)
Explanation: When working with tibbles versus base R data frames, one of the most important distinctions to understand is how the $ operator handles partial matching. Base R data frames perform partial matching with $, meaning df$cust might successfully return a column named customer. Tibbles deliberately disable this behavior. In tibble's design philosophy, partial matching is considered a source of silent bugs — code that appears to work but does something unexpected. So when you write tb$cust on a tibble that has columns customer and custom, tibble's $ operator requires an exact match. Since neither column is literally named cust, tibble returns NULL and emits a warning telling you no column with that name exists. This makes D the correct answer. Answer A is wrong because it describes base R data frame behavior — partial matching returning the first alphabetical or positional match. Tibbles don't do this. Answer B is also wrong for the same reason: even if tibble did partial-match, there's no rule that the "shortest matching name" wins; that logic isn't part of R's partial matching system at all. Answer C is wrong because $ always returns a single column (a vector), never a multi-column tibble — even if ambiguity were handled, returning two columns isn't how $ works in any context. A useful rule of thumb: tibbles are strict, data frames are lenient. Whenever a question contrasts tibble and data frame behavior, watch for partial matching, dropping dimensions, and type coercion — these are the three classic areas where tibbles enforce stricter rules than base R.

Question 8

Consider tibble::tibble(group = c("A", "B"), active = TRUE, score = 1:3).

What happens when this expression is evaluated?

  1. A six-row tibble is created by recycling all columns to a common multiple.
  2. A three-row tibble is created by recycling group and active as needed.
  3. An error occurs because the non-scalar columns have incompatible sizes of two and three. (correct answer)
  4. A two-row tibble is created after the third value of score is silently discarded.
Explanation: When constructing a tibble, you need to think carefully about column recycling rules. Unlike base R data frames, which recycle columns to any multiple, tibbles enforce a stricter rule: only scalar values (length-1 vectors) are recycled to match longer columns. Non-scalar columns must all share the exact same length. In this expression, group = c("A", "B") has length 2, active = TRUE has length 1 (a scalar), and score = 1:3 has length 3. The scalar active could theoretically recycle to either 2 or 3 — but group and score are both non-scalar with different lengths (2 vs. 3). Since tibble requires all non-scalar columns to have identical lengths, this triggers an error immediately. That makes C the correct answer. A describes base R data.frame() behavior more loosely — recycling to a common multiple — which tibble explicitly does not do. B sounds plausible because active = TRUE would recycle, but it misrepresents tibble's rule: the conflict between group (length 2) and score (length 3) causes failure before any recycling of active can save the situation. D invents a silent truncation behavior that neither tibble nor base R applies here — tibble never silently discards data. As a study tip, remember the tibble recycling rule as: "length-1 or same length, nothing else." Whenever you see a tibble constructor with columns of mixed lengths, check immediately whether any non-scalar columns differ — if they do, expect an error.

Question 9

A programmer creates tb <- tibble::tibble(x = 1:3, y = x * 2, z = y - x).

What values are stored in column z?

  1. c(1, 2, 3), because later columns can use columns created earlier in tibble(). (correct answer)
  2. c(2, 4, 6), because z retains the most recently created column unchanged.
  3. c(-1, -2, -3), because x is subtracted from y before y is doubled.
  4. No values are stored because columns inside tibble() cannot reference one another.
Explanation: When you see a question about creating tibbles in R, focus on one of tibble()'s most useful features: sequential column construction. Unlike data.frame(), tibble() evaluates each column definition in order, meaning later columns can reference columns defined earlier in the same call. Here's how the construction unfolds step by step. First, x = 1:3 creates the vector c(1, 2, 3). Next, y = x * 2 references that freshly created x, producing c(2, 4, 6). Finally, z = y - x uses both previously defined columns — subtracting c(1, 2, 3) from c(2, 4, 6) — yielding c(1, 2, 3). So A is correct: z stores c(1, 2, 3). Choice B suggests z simply copies the most recently created column unchanged, which misreads the expression entirely — z = y - x is a subtraction operation, not an assignment of y. Choice C claims that x is subtracted from y before y is doubled, but that reverses the evaluation order: y is fully computed as x * 2 before z ever references it. Choice D reflects a common misconception carried over from base R's data.frame(), where forward-referencing columns mid-construction does fail — but tibble() was explicitly designed to support this sequential referencing. A helpful study tip: whenever you spot column definitions inside tibble() that reference sibling columns, remember that evaluation flows top to bottom, and each column becomes available immediately after it's defined. This behavior is a deliberate advantage of tibble() over data.frame().

Question 10

Consider tb <- tibble::tibble(id = 1:2, ratio = c(1, 2.5), when = as.Date("2025-01-01") + 0:1, group = factor(c("A", "B"))).

Which sequence of type abbreviations appears beneath the column names when tb is printed?

  1. <int>, <dbl>, <date>, and <fct> (correct answer)
  2. <dbl>, <dbl>, <chr>, and <chr>
  3. <int>, <int>, <date>, and <chr>
  4. <num>, <num>, <dttm>, and <fct>
Explanation: When a tibble prints in R, it displays a short type abbreviation under each column name. Knowing how R stores different data types — and how tibbles label them — is exactly what this question tests. Walk through each column in tb. The id column is created with 1:2, which generates an integer sequence, so its abbreviation is <int>. The ratio column uses c(1, 2.5) — because 2.5 is a decimal, R stores the entire vector as double (floating-point), giving <dbl>. The when column is built with as.Date(...), which produces a Date object, labeled <date>. Finally, factor(c("A", "B")) creates a factor, abbreviated <fct>. That sequence — <int>, <dbl>, <date>, <fct> — matches A, making it the correct answer. B is wrong on multiple counts: it shows <dbl> for id (ignoring that 1:2 produces integers, not doubles) and replaces both the date and factor columns with <chr>, as if they were plain character strings. C gets id right but misclassifies ratio as <int> — mixing a decimal into a vector forces the type to double, not integer — and wrongly labels the factor as <chr>. D invents abbreviations (<num>, <dttm>) that don't apply here: <num> isn't a tibble label, and <dttm> is reserved for date-time (POSIXct) objects, not plain Date objects. A reliable study tip: remember that 1:n always yields <int>, any mix with decimals yields <dbl>, as.Date() gives <date> (not <dttm>), and factor() gives <fct> — four distinct types that tibbles label precisely.