Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

R (4.6)  Module 2 – Vectors, types and missing values

Vector arithmetic, recycling and sequences

Do arithmetic on whole R vectors, predict how recycling pairs vectors of different lengths, and build sequences and totals with seq_len(), rep() and cumsum().

  • Beginner
  • 10 minutes
  • Examples run with R 4.6.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 10 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Apply arithmetic and maths functions element by element to whole vectors
  • Predict recycling when vectors of different lengths meet, and when R warns
  • Generate sequences with :, seq(), seq_len(), seq_along() and rep()
  • Compute running totals, changes and tables with cumsum(), cumprod(), diff() and outer()

Before you start

What you’ll learn · Before you start

What you will learn

  • Apply arithmetic and maths functions element by element to whole vectors
  • Predict recycling when vectors of different lengths meet, and when R warns
  • Generate sequences with :, seq(), seq_len(), seq_along() and rep()
  • Compute running totals, changes and tables with cumsum(), cumprod(), diff() and outer()

Before you start

On this page

Converting 1,000 heights from centimetres to metres takes one line in R, heights_cm / 100, and no loop, because arithmetic works on every element of a vector at once. When two vectors of different lengths meet, R repeats the shorter one, and it warns about only some mismatches: 1:5 + 1:2 gets a warning, while 12 months paired with 4 quarterly factors gets none.

The runs on this page, from R 4.6.1, show how element-by-element arithmetic works, when recycling helps and when it hides a mistake, how to count positions in a way that survives an empty vector, how rep() builds the columns of an experimental design, and how cumsum(), diff() and outer() turn values into running totals, changes and tables.

Arithmetic and maths functions work on every element

heights_cm / 100 divides each of the four heights by 100 and returns four results. An Introduction to R puts the rule in one line: in an arithmetic expression the operations are performed element by element. Two vectors of the same length are paired position by position, so c(10, 20, 30) + c(1, 2, 3) is 11 22 33. Arithmetic like this, applied to a whole vector with no loop written by you, is called vectorised: Applied to every element of a vector at once, with no loop written by you. R's arithmetic, comparisons and most maths functions, such as sqrt() and round(), are vectorised., and so are most maths functions: sqrt(), log10(), exp() and round() each return one result per element.

vectorised.R, typed at the R console Python · vectorised_session.py
from session import run, version

version()
# R reads vectorised.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f vectorised.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f vectorised.R
> # One line converts every height, with no loop.
> heights_cm <- c(150, 162, 171, 158)
> heights_cm / 100
[1] 1.50 1.62 1.71 1.58
> # Two vectors of the same length meet element by element.
> c(10, 20, 30) + c(1, 2, 3)
[1] 11 22 33
> c(10, 20, 30) * c(1, 2, 3)
[1] 10 40 90
> # Maths functions work on every element too.
> sqrt(c(4, 9, 16))
[1] 2 3 4
> round(c(1.234, 5.678), 1)
[1] 1.2 5.7
> log10(c(1, 10, 100))
[1] 0 1 2
> # The types of the inputs decide the type of the result.
> typeof(1:3 * 2L)
[1] "integer"
> typeof(1:3 * 2)
[1] "double"
> typeof(6L / 2L)
[1] "double"
> # %/% divides and rounds down; %% gives the remainder.
> c(7, 8, 9) %/% 2
[1] 3 4 4
> c(7, 8, 9) %% 2
[1] 1 0 1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vectorised_session.py

The last lines show that the inputs decide the type of the result. An integer times an integer stays an integer, an integer times the double 2 becomes a double, and / always gives a double, even for 6L / 2L. %/% divides and rounds down and %% gives the remainder, so c(7, 8, 9) %/% 2 is 3 4 4 and c(7, 8, 9) %% 2 is 1 0 1.

Write the vector version first

A loop such as for (i in 1:4) m[i] <- heights_cm[i] / 100 gives the same four values, with a counter, an index and a result vector that can each go wrong. heights_cm / 100 cannot miss an element or stop one short.

Checkpoint

Check: Arithmetic on whole vectors

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    c(10, 20, 30) - c(1, 2, 3)
    Show the answer: Question 1 of 2

    Answer: 9 18 27

    Element by element: 10 - 1, 20 - 2 and 30 - 3 give 9 18 27.

  2. Question 2 of 2 Which of these lines returns an integer vector?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 1:3 * 2L

    The inputs decide the type: integer with integer stays integer for +, - and , while a double input or / gives a double. The run showed typeof(1:3 2L) as "integer" and typeof(6L / 2L) as "double".

A shorter vector is recycled, and only an uneven fit warns

1:6 + 1:2 adds two vectors of different lengths and still returns six values. R repeats the shorter vector from its start until it is as long as the longer one, which is called recycling: R's rule for vectors of different lengths in an element-by-element operation: the shorter one is repeated from its start until it is as long as the longer one. R warns only when the lengths do not divide evenly.. The help page ?Arithmetic gives the rule and its one exception: shorter vectors are recycled as needed, with a warning only when they are recycled fractionally, and a zero-length vector makes the whole result zero-length. Step through two sums:

Interactive · step by step How R recycles the shorter vector Step through 1:6 + 1:2, then 1:5 + 1:2. Each row is one pair of elements; dashed lines mark the repeated copies.
How R recycles the shorter vector, step 5 of 5. Showing 1:6 (now 1:5), 1:2, recycled, 1 (sum 2), 2 (sum 4), 3 (sum 4), 4 (sum 6), 5 (sum 6), 1, 2, 1, 2, 1. In focus: 1:2, recycled.1:6now 1:51:2, recycled1sum 22sum 43sum 44sum 65sum 612121

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. Two lengths. 1:6 has six elements and 1:2 has two. Adding them element by element needs a partner for each of the six, and only the first two have one.
  2. Repeat from the start. R repeats 1:2 from its first element until it is as long as 1:6, so the partners are 1 2 1 2 1 2. Six is a multiple of two, so the copies fit exactly.
  3. 1:6 + 1:2. Each pair is added, and R prints 2 4 4 6 6 8 with no message at all, because the fit was even.
  4. 1:5 + 1:2. With five elements the third copy of 1:2 is cut after its first value. R still pairs them, 1 2 1 2 1, and prints 2 4 4 6 6.
  5. The warning. Five is not a multiple of two, so R adds a warning: longer object length is not a multiple of shorter object length. An even fit never warns, whether or not it was what you meant.

Recycling is how heights_cm / 100 works at all: the single number 100 is a vector of length 1, recycled to every element. The run below adds a few more cases, then the one that matters most, and its fix:

recycling.R, typed at the R console Python · recycling_session.py
from session import run, version

version()
# R reads recycling.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f recycling.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f recycling.R
> # A single number is recycled to every element.
> c(5, 10, 15) - 1
[1]  4  9 14
> # A shorter vector is repeated from its start.
> 1:6 + 1:2
[1] 2 4 4 6 6 8
> 1:6 + c(100, 200, 300)
[1] 101 202 303 104 205 306
> # An uneven fit still gives an answer, with a warning.
> 1:5 + 1:2
[1] 2 4 4 6 6
Warning message:
In 1:5 + 1:2 :
  longer object length is not a multiple of shorter object length
> # A zero-length vector gives a zero-length answer.
> 1:3 + numeric(0)
numeric(0)
> # Even recycling is silent, whatever you meant by it.
> monthly <- rep(100, 12)
> quarterly_factor <- c(0.9, 1.0, 1.1, 1.2)
> monthly * quarterly_factor
 [1]  90 100 110 120  90 100 110 120  90 100 110 120
> # One factor per quarter: repeat each one for its 3 months.
> factors <- rep(quarterly_factor, each = 3)
> stopifnot(length(monthly) == length(factors))
> monthly * factors
 [1]  90  90  90 100 100 100 110 110 110 120 120 120

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 recycling_session.py

monthly * quarterly_factor was meant to apply one factor per quarter to 12 monthly figures. Twelve is a multiple of four, so R recycled the 4 factors three times without a word, and paired January with the first quarter’s factor, February with the second’s, March with the third’s and April with the fourth’s: 90, 100, 110, 120, then the same again. The last lines build the 12 factors that were meant, three months per quarter, and check the lengths first.

Taking silence for agreement

No warning only means that the lengths fit evenly, not that the pairing is the one you meant. Make the intended vector explicitly, factors <- rep(quarterly_factor, each = 3), so both vectors have 12 elements, and check lengths that must match with stopifnot(length(monthly) == length(factors)), as the run does.

The same silence covers every even fit, 6 values with 3 or 100 with 25, so the check has to come from you.

Key idea

R recycles the shorter vector from its start to the length of the longer one; it warns only when the lengths do not divide evenly, so an even fit with the wrong pairing passes in silence.

Checkpoint

Check: Recycling, and when R warns

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    c(1, 2, 3, 4) * c(10, 100)
    Show the answer: Question 1 of 2

    Answer: 10 200 30 400

    The shorter vector is repeated from its start until it has four elements, 10 100 10 100, and the pairs are multiplied: 1 × 10, 2 × 100, 3 × 10 and 4 × 100.

  2. Question 2 of 2 Which of these lines make R warn? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 2 of 2

    Answer:

    • 1:5 + 1:2
    • 1:6 + 1:4

    R warns only when the longer length is not a multiple of the shorter one. 6 and 4, 5 and 2 do not divide evenly; 6 and 3, 12 and 4 do, and are recycled without a message.

Count positions in a way that survives an empty vector

1:5 counts up and 5:1 counts down, which is exactly the trouble with 1:length(x): when x is empty its length is 0, and 1:0 counts down to give the two numbers 1 0. A loop over it runs twice on a vector that has nothing in it. seq_along(x) gives the positions of x and seq_len(n) the numbers 1 to n, and both give integer(0), no numbers at all, when there is nothing to count:

Expression x holds 3 values x is empty
1:length(x) 1 2 3 1 0
seq_len(length(x)) 1 2 3 integer(0)
seq_along(x) 1 2 3 integer(0)
sequences.R, typed at the R console Python · sequences_session.py
from session import run, version

version()
# R reads sequences.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f sequences.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f sequences.R
> # 1:n counts up, or down when n is below 1.
> 1:5
[1] 1 2 3 4 5
> 5:1
[1] 5 4 3 2 1
> # An empty vector has length 0, so 1:length(x) is 1 0.
> x <- numeric(0)
> length(x)
[1] 0
> 1:length(x)
[1] 1 0
> # A loop over 1:length(x) runs twice on an empty vector,
> # and reads x[1] and x[0], which do not exist.
> for (i in 1:length(x)) print(x[i])
[1] NA
numeric(0)
> # seq_along() and seq_len() give no positions at all.
> seq_along(x)
integer(0)
> seq_len(length(x))
integer(0)
> for (i in seq_along(x)) print(x[i])
> # With three values, every form gives 1 2 3.
> x <- c(4.2, 3.9, 5.1)
> seq_along(x)
[1] 1 2 3
> # seq() takes a step, or the length you want.
> seq(2, 11, by = 3)
[1]  2  5  8 11
> seq(0, 1, length.out = 5)
[1] 0.00 0.25 0.50 0.75 1.00

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 sequences_session.py

On the empty vector the loop over 1:length(x) ran twice, printing NA for x[1] and numeric(0) for x[0], while the loop over seq_along(x) printed nothing, which is right. seq() covers the other regular sequences: seq(2, 11, by = 3) steps from 2 to 11 in threes, and seq(0, 1, length.out = 5) asks for five evenly spaced values and works out the step, 0.25, itself.

Looping over 1:length(x)

for (i in 1:length(x)) works on every vector except an empty one, where it runs for i = 1 and i = 0, reading x[1] as NA and x[0] as an empty vector. Write for (i in seq_along(x)), which simply does not run.

Checkpoint

Check: Counting positions safely

  1. Question 1 of 2 x <- numeric(0). How many times does the body of for (i in 1:length(x)) run?

    Type a number.

    A hint

    What is 1:0?

    Show the answer: Question 1 of 2

    Answer: 2 times

    length(x) is 0, and 1:0 counts down to give 1 0, so the loop runs twice, with i = 1 and then i = 0. for (i in seq_along(x)) would not run at all.

  2. Question 2 of 2 What does this return?

    Read the code, then choose one answer.

    seq(10, 20, length.out = 3)
    Show the answer: Question 2 of 2

    Answer: 10 15 20

    With length.out = 3, seq() works out the step itself: (20 - 10) / (3 - 1) = 5, giving 10, 15 and 20.

rep() repeats values to build the columns of a design

An experiment with 3 blocks and 2 treatments has 6 plots, and its data need a block column and a treatment column that line up row by row. rep() builds both. each repeats every value before moving on, and times repeats the whole vector. Step through the two calls, then read the rows across:

Interactive · step by step Building the columns of a design with rep() Step through the two rep() calls of the design example. Each row is one plot of the trial, read across.
Building the columns of a design with rep(), step 4 of 4. Showing block, treatment, 1, 1, 2, 2, 3, 3, ctrl, trt, ctrl, trt, ctrl, trt. In focus: 1, 1, trt.blockrep(1:3, each = 2)treatmentrep(..., times = 3)112233ctrltrtctrltrtctrltrtwith each = 3 this row is ctrl

The drawing shows the whole scene; its 4 steps are listed below.

Every step as text
  1. each = 2. each = 2 repeats every value twice before moving on, so rep(1:3, each = 2) gives 1 1 2 2 3 3. Rows 1 and 2 belong to block 1.
  2. times = 3. times = 3 repeats the whole vector three times, so rep(c("ctrl", "trt"), times = 3) gives ctrl trt ctrl trt ctrl trt.
  3. Read across. Both columns have six values, so row i of one belongs with row i of the other. Every block holds ctrl once and trt once, which makes the design balanced; paste(block, treatment) prints 1 ctrl, 1 trt, 2 ctrl and so on.
  4. The wrong argument. Made with each = 3 instead, the treatments would be ctrl ctrl ctrl trt trt trt. Block 1 would get ctrl twice and never trt, and R would not warn, because the lengths still match.

The run builds the same columns, then a trial with 4 arms over 7 days, whose 28 rows come from each = 7 for the arm and times = 4 for the day:

design.R, typed at the R console Python · design_session.py
from session import run, version

version()
# R reads design.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f design.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f design.R
> # A balanced design: 3 blocks, each with both treatments.
> block <- rep(1:3, each = 2)
> treatment <- rep(c("ctrl", "trt"), times = 3)
> block
[1] 1 1 2 2 3 3
> treatment
[1] "ctrl" "trt"  "ctrl" "trt"  "ctrl" "trt" 
> paste(block, treatment)
[1] "1 ctrl" "1 trt"  "2 ctrl" "2 trt"  "3 ctrl" "3 trt" 
> # Different counts for each value, or a length to stop at.
> rep(c("ctrl", "trt"), times = c(2, 4))
[1] "ctrl" "ctrl" "trt"  "trt"  "trt"  "trt" 
> rep(c("ctrl", "trt"), length.out = 5)
[1] "ctrl" "trt"  "ctrl" "trt"  "ctrl"
> # A trial with 4 arms over 7 days has 28 rows.
> arm <- rep(c("A", "B", "C", "D"), each = 7)
> day <- rep(seq_len(7), times = 4)
> length(arm)
[1] 28
> head(paste(arm, day), 9)
[1] "A 1" "A 2" "A 3" "A 4" "A 5" "A 6" "A 7" "B 1" "B 2"
> # sequence() joins several counts from 1: 1:3, then 1:2.
> sequence(c(3, 2))
[1] 1 2 3 1 2
> # Two starts with one length: R 4.6 warns by default ...
> sequence(2, from = c(1, 10))
[1] 1 2
Warning message:
In sequence.default(2, from = c(1, 10)) :
  length(nvec) 1 < 2 = max(length(from), length(by)) -- future R`s default 'recycle = TRUE' will recycle 'nvec'
> # ... and recycles the length when you ask it to.
> sequence(2, from = c(1, 10), recycle = TRUE)
[1]  1  2 10 11

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 design_session.py

times can also be a vector with one count per value, so rep(c("ctrl", "trt"), times = c(2, 4)) gives two controls and four treated plots, and length.out stops the repetition at a length, mid-copy if need be. sequence() joins several counts from 1 into one vector: sequence(c(3, 2)) is 1 2 3 1 2.

New in R 4.6.0: sequence(recycle =)

R 4.6.0 gave sequence() a recycle argument. With the default, FALSE, one length and two starts give only the first sequence, 1 2, and the run shows the warning that a future R will change this default. With recycle = TRUE, R recycles the length too and gives 1 2 10 11. Set it explicitly in code that uses more starts than lengths.

Checkpoint

Check: Repeating values with rep()

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    rep(c("a", "b"), each = 2)
    Show the answer: Question 1 of 2

    Answer: "a" "a" "b" "b"

    each = 2 gives every value twice in a row, "a" "a" "b" "b". times = 2 would give the whole vector twice, "a" "b" "a" "b".

  2. Question 2 of 2 A trial has 5 blocks and 3 treatments, each treatment once in every block. How many values does rep(1:5, each = 3) return?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 15 values

    Each of the 5 block numbers is repeated 3 times, once per treatment, which gives the 15 rows of the design. The treatment column, rep(treatments, times = 5), has the same 15 values.

cumsum(), diff() and outer() give running totals, changes and tables

A week of rainfall, 12 0 5 30 8 0 21 mm, becomes a running total with cumsum(): 12 12 17 47 55 55 76. Its relatives work the same way along the vector: cumprod() multiplies as it goes, and cummax() and cummin() keep the highest and lowest value so far. diff() goes the other way, from values to the change between neighbours: diff(c(1, 4, 9, 16)) is 3 5 7, and differences = 2 takes the changes of the changes, 2 2. outer() pairs every value of one vector with every value of another and returns the table of results.

running.R, typed at the R console Python · running_session.py
from session import run, version

version()
# R reads running.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f running.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f running.R
> # Daily rainfall in mm, and the running total.
> rain <- c(12, 0, 5, 30, 8, 0, 21)
> cumsum(rain)
[1] 12 12 17 47 55 55 76
> # diff() gives the change from one value to the next.
> diff(c(1, 4, 9, 16))
[1] 3 5 7
> diff(c(1, 4, 9, 16), differences = 2)
[1] 2 2
> diff(cumsum(rain))
[1]  0  5 30  8  0 21
> # cummax() keeps the highest value so far.
> cummax(c(3, 1, 4, 1, 5))
[1] 3 3 4 4 5
> # cumprod() multiplies as it goes: 10,000 at 8 % a year.
> round(cumprod(rep(1.08, 10)) * 10000)
 [1] 10800 11664 12597 13605 14693 15869 17138 18509 19990 21589
> # outer() pairs every value of one vector with every value
> # of another: daily doses in mg, total after each day.
> daily <- c(A = 0, B = 5, C = 10, D = 20)
> outer(daily, 1:7)
  [,1] [,2] [,3] [,4] [,5] [,6] [,7]
A    0    0    0    0    0    0    0
B    5   10   15   20   25   30   35
C   10   20   30   40   50   60   70
D   20   40   60   80  100  120  140

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 running_session.py

diff(cumsum(rain)) gives back every day’s rainfall except the first, because each total minus the one before is that day’s amount. outer(daily, 1:7) multiplies each arm’s daily dose by each day number, so row B reads 5, 10, 15 up to 35 mg after a week.

cumprod(rep(1.08, 10)) * 10000 is a deposit of 10,000 growing by 8 % a year: each year’s balance is the year before times 1.08. The model below computes the same balance; its table gives 10,800 for the first year and 21,589 for the tenth, the values the run printed. Change the rate or the years, then check one value with the same line in your R:

Interactive · change it and see 10,000 growing by 8 % a year: cumprod() as a chart Set a starting amount, a yearly rate, how often interest is added and an amount added at the end of every month.
Balance and money paid in, year by year: amount against years.024681005k10k15k20k25kyearsamountbalancepaid in

10,000 at 8 % a year grows to 21,589 in 10 years; 11,589 of it is interest.

Balance after 10 years 21,589
Paid in 10,000
Interest earned 11,589
Effective yearly rate 8.00 %
The numbers as a table
Balance at the end of each year
YearPaid inBalance
110,00010,800
210,00011,664
310,00012,597
410,00013,605
510,00014,693
610,00015,869
710,00017,138
810,00018,509
910,00019,990
1010,00021,589

Sequence & Series Calculator (AP, GP & Pattern Finder) Check the length and the last term of an arithmetic sequence before you write it as seq(from, to, by).

Checkpoint

Check: Running totals, changes and tables

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    cumsum(c(3, 0, 4))
    Show the answer: Question 1 of 2

    Answer: 3 3 7

    cumsum() keeps one running total per position: 3, 3 and 7. diff() goes the other way and would give -3 and 4.

  2. Question 2 of 2 daily <- c(A = 0, B = 5, C = 10, D = 20). What value is in row C, column 4 of outer(daily, 1:7)?

    Type a number.

    A hint

    outer() multiplies the row's value by the column's value.

    Show the answer: Question 2 of 2

    Answer: 40 mg

    outer() multiplies every value of daily by every day number. Row C holds 10 mg a day and column 4 is day 4, so the cell is 10 × 4 = 40 mg, the total after four days.

Practise: predict, then check

The lines below use every idea of this page. Write down what you expect each one to print before you look at the run.

Predict first

For x <- c(2, 4, 6, 8), predict x * c(1, -1), x + 1:3 (and whether R warns), seq(1, 10, length.out = 4), rep(1:2, each = 2, times = 2), cumsum(x) and diff(x). Then type them in your own R and compare.

practice.R, typed at the R console Python · practice_session.py
from session import run, version

version()
# R reads practice.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f practice.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f practice.R
> x <- c(2, 4, 6, 8)
> x * c(1, -1)
[1]  2 -4  6 -8
> x + 1:3
[1] 3 6 9 9
Warning message:
In x + 1:3 :
  longer object length is not a multiple of shorter object length
> seq(1, 10, length.out = 4)
[1]  1  4  7 10
> rep(1:2, each = 2, times = 2)
[1] 1 1 2 2 1 1 2 2
> cumsum(x)
[1]  2  6 12 20
> diff(x)
[1] 2 2 2

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 practice_session.py

c(1, -1) was recycled evenly and flipped every second sign; 1:3 did not fit four elements, so R warned; seq() worked out a step of 3; each and times together repeat each value, then the whole result; and diff(cumsum(x)) would give back 4, 6 and 8.

Last, a round of questions on the five ideas above. The weakest idea comes first, a right answer brings a harder question, and a missed one comes back at the end:

Practice that adapts to you

Practise this lesson

11 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 11 What does sqrt(c(9, 16, 25)) return?

    Choose one answer.

    Show the answer: Question 1 of 11

    Answer: 3 4 5

    Maths functions such as sqrt(), log10(), exp() and round() work element by element, so the result is 3 4 5.

  2. Question 2 of 11 prices <- c(250, 400, 120). Which line adds 18 % tax to every price and rounds each result to a whole number?

    Choose one answer.

    Show the answer: Question 2 of 11

    Answer: round(prices * 1.18)

    prices * 1.18 gives 295, 472 and 141.6, and round() makes them 295, 472 and 142. Every step works on all three prices at once.

  3. Question 3 of 11 When does R warn about recycling?

    Choose one answer.

    Show the answer: Question 3 of 11

    Answer: When the longer length is not a multiple of the shorter one

    R warns only when the lengths do not divide evenly. That is why a wrong pairing with lengths that do divide evenly passes unnoticed.

  4. Question 4 of 11 monthly holds 12 monthly figures and quarterly_factor 4 factors, one per quarter. Which vector applies each quarter's factor to its three months when multiplied by monthly?

    Choose one answer.

    Show the answer: Question 4 of 11

    Answer: rep(quarterly_factor, each = 3)

    Recycling repeats the whole vector, which pairs months with quarters in turn. Making the 12-element vector yourself with each = 3 gives the pairing you meant, and the lengths then match exactly.

  5. Question 5 of 11 What does this return?

    Read the code, then choose one answer.

    seq_along(c("x", "y", "z"))
    Show the answer: Question 5 of 11

    Answer: 1 2 3

    seq_along(x) is 1, 2, … up to length(x), and integer(0) for an empty x.

  6. Question 6 of 11 A function must return the positions of a vector v of any length, including length 0. Which expression is right for every case?

    Choose one answer.

    Show the answer: Question 6 of 11

    Answer: seq_along(v)

    Only seq_along(v), or seq_len(length(v)), handles length 0. Anything built on from:to counts down when to is below from.

  7. Question 7 of 11 What does this return?

    Read the code, then choose one answer.

    rep(c("x", "y"), times = c(3, 1))
    Show the answer: Question 7 of 11

    Answer: "x" "x" "x" "y"

    times = c(3, 1) repeats the first value three times and the second once.

  8. Question 8 of 11 What does this return?

    Read the code, then choose one answer.

    rep(1:3, length.out = 7)
    Show the answer: Question 8 of 11

    Answer: 1 2 3 1 2 3 1

    The vector is repeated, 1 2 3 1 2 3 1 2 3 …, and cut at the seventh value.

  9. Question 9 of 11 Which function turns daily values into a running total?

    Choose one answer.

    Show the answer: Question 9 of 11

    Answer: cumsum()

    cumsum(c(12, 0, 5)) is 12 12 17: one running total per day.

  10. Question 10 of 11 What does this return?

    Read the code, then choose one answer.

    diff(c(10, 15, 12))
    Show the answer: Question 10 of 11

    Answer: 5 -3

    diff(x) is x[2] - x[1], x[3] - x[2] and so on: 5 and -3, one fewer value than x.

  11. Question 11 of 11 What does this return?

    Read the code, then choose one answer.

    x <- c(4, 1, 6)
    diff(cumsum(x))
    Show the answer: Question 11 of 11

    Answer: 1 6

    Each running total minus the one before it is that position's value, so diff(cumsum(x)) gives back every value of x except the first: 1 and 6.

Interview questions

Warm-up: what is recycling in R, and when does R warn about it?

When an element-by-element operation such as + or * meets two vectors of different lengths, R repeats the shorter one from its start until it is as long as the longer one, and then pairs the elements. That is recycling. A single number is the everyday case: in x * 2 the 2 is recycled to every element of x. R warns only when the longer length is not a multiple of the shorter one, as in 1:5 + 1:2, and even then it still returns a result. When the lengths divide evenly, as with 12 values and 4, R recycles in silence, so the absence of a warning never proves that the pairing was the one you intended. When two vectors must match element for element, check their lengths yourself.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    A report function loops with for (i in 1:length(ids)) and passed every test. Called in production with an empty ids vector, it wrote two rows of nonsense. Explain exactly what happened on each pass, and how you would make the function safe for any input.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    Twelve monthly sales figures were multiplied by a vector of seasonal factors, and the yearly total looked plausible. Later someone noticed the factors had 4 values, one per quarter. Why did R not complain, which month got which factor, and how would you stop this kind of mistake?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Arithmetic and most maths functions are vectorised: they work element by element on whole vectors, and the input types decide whether the result is an integer or a double.
  • When lengths differ, R recycles the shorter vector from its start and warns only when the lengths do not divide evenly, so an even fit with the wrong pairing gives no warning.
  • 1:length(x) is 1 0 for an empty x, so loops use seq_along(x) or seq_len(n), which give no positions at all when there is nothing to count; seq() makes other regular sequences by step or by length.
  • rep() repeats values with each, times and length.out, which is how the columns of a design are built, and sequence() joins several counts from 1.
  • cumsum(), cumprod() and cummax() accumulate along a vector, diff() turns values into changes, and outer() builds a table from every pair of values.

Terms in this lesson

recycling
R's rule for vectors of different lengths in an element-by-element operation: the shorter one is repeated from its start until it is as long as the longer one. R warns only when the lengths do not divide evenly.
vectorised
Applied to every element of a vector at once, with no loop written by you. R's arithmetic, comparisons and most maths functions, such as sqrt() and round(), are vectorised.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.