-2

I have written a code to loop through, get the inputs and add value to

f1 <- file("stdin")
open(f1)
arr = c(0, 0, 0, 0, 0)
for(i in 1:3){
#user will provide the input 3 times. It will be a space separated input. Each input will have 3 numbers. 
#1st will indicate the starting index. 
#2nd will indicate the ending index. 
#And 3rd will indicate the value to be added between the starting and ending index

  inp1 = readLines(f1, n = 1, warn = FALSE)
  spl = strsplit(inp1, " ")[[1]]
  a = as.numeric(spl[1]) #start index
  b = as.numeric(spl[2]) #end index
  k = as.numeric(spl[3]) #value to be added

  arr[a:b] = arr[a:b] + k
}
arr

Sample Input:

1 3 5

1 3 5

2 4 5

Expected Output:

10 15 15 5 0

Is there a way to improve its performance, may be by eliminating the for loop.

Leo
  • 5,017
  • 6
  • 32
  • 55
  • 4
    What's `f1`? What is your goal here? Explain it a bit. Don't just dump some code... – Sotos Jun 27 '18 at 12:01
  • 1
    An obvious simplification would be to read in the file just once, `strsplit` all its lines in one call and then loop through `spl[[1]]`, `spl[[2]]`, etc. – Rui Barradas Jun 27 '18 at 12:05
  • @Sotos - I have updated the code – Leo Jun 27 '18 at 12:09
  • 1
    `i` isn't used in the loop. So why not no loop, and `arr[a:b] = arr[a:b] + k * 3`. Is `[[1]]` supposed to read `[[i]]`? – Axeman Jun 27 '18 at 12:09
  • 2
    [How to make a great R reproducible example?](http://stackoverflow.com/questions/5963269) – Sotos Jun 27 '18 at 12:11
  • You are doing input/output (call to `readLines`), which will take a lot of time anyway. Thus I wouldn't care too much about execution time when deciding to avoid the loop or not: the impact will only be minor. The most important criterion might be readability of your code. – Pierre Gramme Jun 27 '18 at 12:12
  • 3
    Please explain in *words* what are you trying to do here. I can't understand how your input is related to the output – David Arenburg Jun 27 '18 at 12:14
  • @DavidArenburg: looks like each row of input contains start index, end index and value to be added, wrt the vector `arr[1:5]`. OP wants to accumulate those values in `arr[1:5]`. – smci Jun 27 '18 at 12:18
  • Your input file is whitespace-separated. Your performance sucks because you're reading it line-by-line, `readLines(n=1...)` followed by `strsplit()` followed by three assignments and three `as.numeric` calls is totally unnecessary. Just do `read.table(..., sep="")`. Unless it's a very large file, just read it all in one chunk. – smci Jun 27 '18 at 12:22
  • Also, as to everyone complaining about reproducibility, they're right: you say it's a performance issue, but then you only show three sample lines of input (!). How long is your input file actually? 10^5 lines? longer? Just give us some sample parameters that actually reproduce the performance issue. – smci Jun 27 '18 at 12:25
  • @Axeman - In actual scenario the `i` will be looping through `1:n` and for each iteration different values will be there for `a`, `b` and `k`. Hence we cannot do `k*3`. – Leo Jun 27 '18 at 12:32
  • @David - Provided required comments in the code. – Leo Jun 27 '18 at 12:37
  • @smci - It will be maximum `2 * 10^5` lines long. – Leo Jun 27 '18 at 12:41
  • Sorry, but your comments don't shed any light on is `i` a row-index or a column-index? What is "`i` will be looping through `1:n`" supposed to mean? Is `i` supposed to count three space-separated columns on each single line of input? Is each line the start,end,value tuple `a,b,k`? Please show us (say) 10 lines of input and the corresponding output. Otherwise this question should be closed for being seriously unclear. – smci Jun 27 '18 at 12:43

2 Answers2

1

This works:

We put the strsplit outside of the loop, then use sapply to create an output matrix and get the rowSums.

arr = rep(0, 5)
inp1 <- c("1 3 5", "1 3 5", "2 4 5")
spl <- lapply(strsplit(inp1, " "), as.numeric)

rowSums(sapply(spl, function(x){
  arr[x[1]:x[2]] <- arr[x[1]:x[2]] + x[3]
  return(arr)
}))

[1] 10 15 15  5  0

To scale this up for multiple inp1, you can use a nested list and just wrap another lapply call around the loop.

LAP
  • 6,605
  • 2
  • 15
  • 28
  • 1
    You can directly read a row of three integers with `scan(what = list('integer','integer','integer'))`. No need for `lapply(strsplit(inp1, " "), as.numeric)` – smci Jun 27 '18 at 13:04
1

You want to read lines of user input, three whitespace-separated columns: start-index, end-index, value where the two indices are in the range 1:5.

arr <- rep(0, 5)

input_to_vector <- function(si, ei, val) {
          tmp <- rep(0, 5)
          tmp[si:ei] <- val
          return(tmp)
      }

Read your input line directly with `scan(what = list('integer','integer','integer'))`

for (inp1 in scan(what = list('integer','integer','integer'))) { ... }

Then lapply/sapply input_to_vector on that input.

Sum the output (column-wise).
smci
  • 32,567
  • 20
  • 113
  • 146