Scheme / Racket Vector in Vector transformation

元气小坏坏 提交于 2020-01-05 10:27:21

问题


I'm having a problem transforming a vector like this:

#(#(1 2 3)#(1 2 3)#(1 2 3)#(1 2 3)#(1 2 3)))

Into one like this:

#(#(1 1 1 1 1) #(2 2 2 2 2) #(3 3 3 3 3))

I wrote a piece of test code but the output is wrong. I went into the debugger and I think I know which line of code cause the problem. I can't seems to find a way to make it work. Any help is greatly appreciated.

(define (test)
  (let* ((table #(#(1 2 3)#(1 2 3)#(1 2 3)#(1 2 3)#(1 2 3)))
         (counter 5)
         (size 3)
         (new-table (make-vector size (make-vector counter #f))))

    (let loop ((sc 0)
               (cc 0))
      (when (not (= cc counter))
        (if (not (= sc size))
            (begin (vector-set! (vector-ref new-table sc) cc (vector-ref (vector-ref table cc) sc))
                   (loop (+ 1 sc) cc))
            (loop 0 (+ 1 cc)))))
    (display new-table))) 

> (test)
#(#(3 3 3 3 3) #(3 3 3 3 3) #(3 3 3 3 3))

回答1:


There's a problem in this part:

(make-vector size (make-vector counter #f))

Why? because you're copying the exact same vector in all off new-table's positions, so whenever you update one value, it'll change all of them at the same time. It's easy to see this:

(define new-table (make-vector 3 (make-vector 3 #f)))
(vector-set! (vector-ref new-table 0) 0 42) ; we modify a single position ...
new-table
=> '#(#(42 #f #f) #(42 #f #f) #(42 #f #f))  ; ... but all of them changed!

You have to initialize the vector at the beginning; a fixed version of your code would look like this:

(let* ((table '#(#(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3)))
       (counter (vector-length table))
       (size (vector-length (vector-ref table 0)))
       (new-table (make-vector size)))
  ; initialization
  (let loop ((i 0))
    (when (< i size)
      (vector-set! new-table i (make-vector counter))
      (loop (+ i 1))))  
  (let loop ((sc 0)
             (cc 0))
    (when (not (= cc counter))
      (if (not (= sc size))
          (begin
            (vector-set! (vector-ref new-table sc) cc
                         (vector-ref (vector-ref table cc) sc))
            (loop (+ 1 sc) cc))
          (loop 0 (+ 1 cc))))
    new-table))

However, the above solution is hard to understand. Fortunately, this seems like a good problem to use Racket's Iterations and Comprehensions, so you don't have to worry about explicitly using recursion for iteration, leading to a much clearer solution:

(let* ((table '#(#(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3)))
       (counter (vector-length table))
       (size (vector-length (vector-ref table 0)))
       (new-table (make-vector size)))
  (for ([sc (in-range size)])
    (vector-set! new-table sc (make-vector counter)) ; initialization
    (for ([cc (in-range counter)])
      (vector-set! (vector-ref new-table sc) cc
                   (vector-ref (vector-ref table cc) sc))))
  new-table)

Either way, the output is as expected:

=> '#(#(1 1 1 1 1) #(2 2 2 2 2) #(3 3 3 3 3))

Note: As it is, this is a procedural programming-style solution, which modifies the new vectors in-place and has the advantage of being fast and efficient (it doesn't create more vectors or lists beyond the strictly necessary), but truth be told, this is not the usual way to solve problems in Scheme. For a functional programming-style solution, more in the spirit of Scheme, see @Ankur's answer.




回答2:


You can also use vector-map to get the desired output:

(define table #(#(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3) #(1 2 3)))

(apply vector-map vector (vector->list table))


来源:https://stackoverflow.com/questions/16641644/scheme-racket-vector-in-vector-transformation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!