And that's one of the reasons why I like functional programming... Firstly, you 
don't really need a new seq for the job you're doing. Your should utilize 
iterating over sections separated by ',' but you can modify them in-place (or 
even better --- directly write them to the file!).

Here is a little benchmark (100 iterations) for a considerable file (23 KB) 
with very few (9) very short (50-60 B for a line) columns:

  * Python: 2.08 s
  * org Nim: 1.44 s
  * KevinGolding's Nim: 1.97 s
  * my Nim version: 0.33 s



Here is the code: 
    
    
    import os, strutils
    
    proc main() =
      var
        pageSize: int = 4096
        input = open(paramStr(1), fmRead, pageSize)
        output = open(paramStr(4), fmWrite, pageSize)
        changeAt = 0
      
      let
        toChange = $paramStr 2
        changeWith = $paramStr 3
      
      var row = input.readLine()
      output.writeLine(row)
      
      block:
        var
          prev = 0
          last = -1
        for i in 0 .. row.len-1:
          prev = last
          last = row.find(',', start=last+1)
          if row[prev+1..last-1] == toChange:
            changeAt = i
            break
      
      while input.readLine(row):  # note: the string buffer is reused
        var
          prev = 0
          last = -1
        for i in 0 .. changeAt:
          prev = last
          last = row.find(',', start=last+1)  # note: no slicing, just indexing
        
        output.writeLine(row[0..prev], changeWith, row[last..row.len])  # note: 
single writeLine
    
    main()
    

Of course one can make it simpler. What's more... it doesn's seem slower at 
all. The only thing I miss here is Rust's "pattern-letting" so I could utilize 
a structure instead of a tuple... Nevertheless, here it comes:
    
    
    import os, strutils
    
    iterator sections(input: string, sep: char = ','): (int,int,int) =
      var
        prev = 0
        last = -1
        i = -1
      while true:
        inc i
        prev = last
        last = input.find(sep, start=last+1)
        yield (i, prev+1, last-1)
        if last == -1:
          break
    
    proc section(input: string, nr: int, sep: char = ','): (int,int) =
      var
        prev = 0
        last = -1
      for i in 0..nr:
        prev = last
        last = input.find(sep, start=last+1)
      result = (prev+1, last-1)
    
    proc findSection(input, name: string, sep: char = ','): (int,int,int) =
      for i,lb,hb in input.sections():
        if input[lb..hb] == name:
          return (i,lb,hb)
    
    proc main() =
      var
        pageSize: int = 4096
        input = open(paramStr(1), fmRead, pageSize)
        output = open(paramStr(4), fmWrite, pageSize)
      
      let
        toChange = $paramStr 2
        changeWith = $paramStr 3
      
      var row = input.readLine()
      output.writeLine(row)
      
      let changeAt = row.findSection(toChange)[0]
      
      while input.readLine(row):
        let (lb, hb) = row.section(changeAt)
        output.writeLine(row[0..lb-1], changeWith, row[hb+1..row.len])
    
    main()
    

Thank you, functional programming!

Reply via email to