Лисп: многомерный массив поэлементных операций - PullRequest
5 голосов
/ 07 ноября 2010

Что такое «правильная» конструкция в Common Lisp для применения поэлементных операций к многомерным массивам?

Следующие примеры должны помочь проиллюстрировать, что я пытаюсь сделать:

A) Предположим, я хочу увеличить каждый элемент массива на единицу:

0 1 2    1 2 3
3 4 5 -> 4 5 6
6 7 8    7 8 9

B) Предположим, я хочу добавить 2 массива:

<code>1 2   -1 -1    0 1
3 4 + -2 -2 -> 1 2
5 6   -3 -3    2 3

C) Предположим, я хочу найти самые большие элементы из нескольких массивов, поэлементно:

<code>max( 0 1 , 4 -1 , 0 0 ) -> 4 1
     2 3   0  0   8 1      8 3

По сути, я думаю, что я ищу какую-то функцию «arraymap», которая будет использоваться следующим образом: (arraymap f A1 A2 ... An), где f принимает n аргументов в качестве входных данных, а Ai - это массивы одинакового размера.

В приведенных выше примерах это будет использоваться так:

A)

<code>(setq M #2A((0 1 2) (3 4 5) (6 7 8)))
(arraymap #'incf M)

В)

<code>(setq M #2A((1 2) (3 4) (5 6)))
(setq N #2A((-1 -1) (-2 -2) (-3 -3)))
(arraymap #'+ M N)
* * С тысячей двадцать восемь)
<code>(setq M #2A((0 1) (2 3)))
(setq N #2A((4 -1) (0 0)))
(setq O #2A((0 0) (8 1)))
(arraymap #'max M N O)

Я пробовал некоторые конструкции с map и loop, но, похоже, это не работает, так как многомерные массивы не являются типом последовательности.

1 Ответ

8 голосов
/ 07 ноября 2010

Для этого есть четыре способа:

  • Написать функцию ARRAY-MAP на основе измерений массива и выполнить итерации по ним.

  • Используйте ROW-MAJOR-AREF , который просматривает массив как вектор.

  • Используйте смещенные одномерные массивы для операций.

Пример использования смещенных массивов:

(defun array-map (function &rest arrays)
  "maps the function over the arrays.
   Assumes that all arrays are of the same dimensions.
   Returns a new result array of the same dimension."
  (flet ((make-displaced-array (array)
           (make-array (reduce #'* (array-dimensions array))
                       :displaced-to array)))
    (let* ((displaced-arrays (mapcar #'make-displaced-array arrays))
           (result-array (make-array (array-dimensions (first arrays))))
           (displaced-result-array (make-displaced-array result-array)))
      (declare (dynamic-extent displaced-arrays displaced-result-array))
      (apply #'map-into displaced-result-array function displaced-arrays)
      result-array)))

Использование его:

CL-USER 3 > (array-map #'1+ #2A((0 1 2) (3 4 5) (6 7 8)))

#2A((1 2 3) (4 5 6) (7 8 9))

CL-USER 4 > (array-map #'+ #2A((1 2) (3 4) (5 6)) #2A((-1 -1) (-2 -2) (-3 -3)) )

#2A((0 1) (1 2) (2 3))
  • Использование внутренних, зависящих от реализации, операций для эффективных операций над массивами.
...