Q:

how to extract blocks of rows without looping in r

I have a huge text file. I would like to extract out the blocks of rows which row indexes are defined in another data frame, such as sub. I have a loop script for it but I would like to find more efficient way (better without looping) for this task. Here is my toy example:
df <- data.frame(value=runif(10000, 0, 10^3))
df$idx <- 1:nrow(df)
sub <- data.frame(start=c(20,50,130,2000),end=c(25,60,150,2030))
sub_data <- data.frame()
for (j in 1:nrow(sub)){
  dt <- df[df$idx >= sub$start[j] & df$idx <= sub$end[j],]
  sub_data <- rbind(sub_data,dt)
}

sub_data

A:

Here is one solution with data.table using non equi join available
since v1.9.8
library(data.table)
dt <- data.table(value=runif(10000, 0, 10^3))
# add index column
dt[, idx := seq_len(.N)]
# create subset table
sub <- data.table(start=c(20,50,130,2000),end=c(25,60,150,2030))
# use data.table non equijoin
dt1 <- dt[sub, on = .(idx >= start, idx <= end)]
head(dt1)
#>        value idx idx.1
#> 1: 820.38637  20    25
#> 2: 262.51398  20    25
#> 3: 900.37408  20    25
#> 4:  74.91815  20    25
#> 5: 507.87825  20    25
#> 6: 547.45235  20    25
# use data.table non equi join but just keep column from dt
dt2 <- dt[sub, .(value, idx = x.idx), on = .(idx >= start, idx <= end)]
head(dt2)
#>        value idx
#> 1: 820.38637  20
#> 2: 262.51398  21
#> 3: 900.37408  22
#> 4:  74.91815  23
#> 5: 507.87825  24
#> 6: 547.45235  25

A:

Here is a solution creating sequence of all id, and then subset the df based on the sequence of id. df2 is the final output. 
IDs <- unlist(lapply(1:nrow(sub), function(i) {sub$start[i]:sub$end[i]}))

df2 <- df[df$idx %in% IDs, ]

Or we can use functions from tidyverse.
library(tidyverse)

sub2 <- sub %>%
  mutate(idx = map2(start, end, `:`)) %>%
  unnest()

df2 <- df %>% semi_join(sub2, by = "idx")

