Mugoya Dihfahsih
Mugoya Dihfahsih

Reputation: 425

Is there a way of summing two vectors with different lengths in Scheme?

Am a beginner to Scheme a dialect of Lisp, am trying to implement a function sum-vector that takes two vectors of numbers as arguments and returns a vector with the sum of the corresponding elements of the input vectors.

I have tried the following code but i can't figure out how to sum two vectors with different lengths. Here is my current code

#lang scheme
(define sum-vector
  (lambda (vec-1 vec-2)
    (let* ((len (vector-length vec-1))
                                       
           (result (make-vector len)))
      (do ((index 0 (+ index 1)))
          ((= index len) result)
        (vector-set! result index
                     (+ (vector-ref vec-1 index)
                        (vector-ref vec-2 index)))))))

(sum-vector (vector 4 6 8 3) (vector 5 6 7))

When i run the above code it works perfectly for vectors with same lengths e.g (sum-vector (vector 4 6 8) (vector 5 6 7)) returns #(9 12 15) I want it to work similarly for different lengths e.g (sum-vector (vector 4 6 8 3) (vector 5 6 7)) should return #(9 11 15 3) but i can't figure out the logic for doing that.

Upvotes: 0

Views: 244

Answers (2)

Shawn
Shawn

Reputation: 52384

Another, Racket-specific way.

Racket has something called comprehensions, which allow for easy iteration over containers. In particular, for/vector returns a vector of the results:

> (define v1 (vector 4 6 8 3))
> (define v2 (vector 5 6 7))
> (for/vector ([e1 v1] [e2 v2]) (+ e1 e2))
'#(9 12 15)

Note that the resulting vector is the length of the shortest container being iterated over. You can tell it to produce a vector of a given length, though:

> (for/vector #:length (vector-length v1) ([e1 v1] [e2 v2]) (+ e1 e2))
'#(9 12 15 0)

It fills in the extra elements with 0. Combine that with vector-copy!, which copies a range of elements from one vector to another at given offsets to copy the extra elements from the larger vector to the smaller (Or do nothing if they're the same length), and you get:

(define (sum-vector v1 v2)
  (let ([sum-helper
         (lambda (short long)
           (let ([result (for/vector #:length (vector-length long)
                                     ([e1 short] [e2 long])
                                     (+ e1 e2))])
             (vector-copy! result (vector-length short)
                           long (vector-length short) (vector-length long))
             result))])
    (if (< (vector-length v1) (vector-length v2))
        (sum-helper v1 v2)
        (sum-helper v2 v1))))

Examples:

> (sum-vector (vector 4 6 8 3) (vector 5 6 7))
'#(9 12 15 3)
> (sum-vector (vector 1 2 3) (vector 1 2 3 4 5 6))
'#(2 4 6 4 5 6)
> (sum-vector (vector) (vector 1 2 3 4 5 6 7 8))
'#(1 2 3 4 5 6 7 8)

Upvotes: 1

Martin Půda
Martin Půda

Reputation: 7568

One possible solution is to append zeros to each vector to make their lengths equal and then use vector-map:

(define (zero-vector len)
  (make-vector len 0))

(define (append-zeros vec max-len)
  (vector-append vec (zero-vector (- max-len (vector-length vec)))))

(define (sum-vector v1 v2)
  (let ((max-len (max (vector-length v1)
                      (vector-length v2))))
    (vector-map +
                (append-zeros v1 max-len)
                (append-zeros v2 max-len))))

Tests:

> (sum-vector (vector 1 2 3) (vector 1 2 3 4 5 6))
'#(2 4 6 4 5 6)
> (sum-vector (vector) (vector 1 2 3 4 5 6 7 8))
'#(1 2 3 4 5 6 7 8)

Upvotes: 2

Related Questions