Optimization, my favorite Nim topic! Runtime of your version for me: 0.766 s res.add board[d[i]]
This line resizes the `res` seq, instead you should allocate it to have the correct size directly. Like this: proc do_something(board: seq[char]): seq[char] = var res = newSeq[char](board.len * Directions.len) for i, p in board: for j, d in Directions: res[i * Directions.len + j] = board[d[i]] return res New runtime: 0.073 s With the new devel branch of Nim you can also use `newSeqOfCap` if you don't want to manually calculate the index: proc do_something(board: seq[char]): seq[char] = var res = newSeqOfCap[char](board.len * Directions.len) for i, p in board: for d in Directions: res.add board[d[i]] return res As a workaround you can also do `var res = newSeq[char](board.len * Directions.len); res.setLen(0)` to achieve the same effect. res = do_something(board) You create a new `res` seq for every call to do_something. Instead you could reuse a single data structure and pass it to `do_something`. But that's probably not what you want to benchmark then. Full code with some cleanup (use implicit result variable, no `$` for echo, arrays instead of seqs, more consts): # Nim example to test execution speed against a Python version import times, os const board = ['0', 'p', '.', 'p', 'P', '.', 'p', 'P', '.', 'p', '.', 'p', 'P', '.', 'p'] NE = [8, 2, 13, 4, 5, 7, 8, 3, 9, 12, 7, 8, 3, 9, 12] Directions = [NE, NE, NE, NE] # for short: in real application the array elements differ proc do_something(board: openarray[char]): seq[char] = result = newSeqOfCap[char](board.len * Directions.len) for i in 0 .. board.high: for d in Directions: result.add board[d[i]] let t0 = cpuTime() var res: seq[char] const count = 100_000 for i in 1..count: res = do_something(board) let t1 = cpuTime() echo "***** Time elapsed for Nim: ", t1 - t0, " Counts: ", count echo res.repr New runtime: 0.065 s For comparison, Python runtime: 0.783 s