Как реализовать вложенный для l oop, который преобразует каждый элемент в двумерном массиве в нули в Clojure - PullRequest
1 голос
/ 16 марта 2020

I sh для реализации (в Clojure) вложенного для l oop, который преобразует каждый элемент в двумерном массиве в ноль. Как и код C, написанный ниже.

void set_to_zero(int n, int m[v][v]) {
          int i, j;
          for(i = 0; i < n; i++)
            for(j = 0; j < n; j++)
              m[i][j] = 0;
        }

Это то, что я смог сделать

(defn trial [n m]
  (loop [i 0
         j 0]
    (if (= i (count (range n)))
      (println m)
      (if (= j (count (range n)))
        (recur i j)
        (assoc-in m[i j] 0)
        )
      )
    )
  )

Это то, что я получаю: т.е. только один элемент изменяется, а остальные остаются неизменными.

(trial 4 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
=> [[0 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]

Обновление

(defn trial [n m]
  (for [i (range n)
         j (range n)]
    (if (> i n)
      m
      (if-not (> j n)
        ;(recur (inc i) j)
        (assoc-in m[i j] 0)
        ;(println i j)
        )
      )
    )
  )

Новый результат

(trial 4 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
=>
([[0 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 0 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 0 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 0] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [0 4 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 0 5 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 0 6] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 0] [6 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [0 1 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 0 8 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 0 9] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 8 0] [3 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 8 9] [0 1 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 0 8 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 0 9]]
 [[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 0]])

В данный момент все элементы изменяются на 0, но выполняется отдельно. хотел бы, чтобы он возвращался как один массив со всеми элементами, равными нулю.

PS Я уверен, что есть более эффективные способы достижения всех нулей в двумерном векторе, но меня особенно интересует форма для l * Метод 1028 *, поскольку он популярен на других языках и может помочь более легко переводить коды с других языков в Clojure (в некоторых случаях).

Спасибо.

Ответы [ 6 ]

2 голосов
/ 16 марта 2020

Во-первых, вы никогда не увеличиваете значения i и j. Таким образом, они никогда не меняются. Таким образом, вы никогда не получите вызов recur.

То, как вы формулируете свой вопрос, создает впечатление, что вы думаете, что вы редактируете вектор на месте. Вы не С каждым assoc-in вы создаете новый вектор. (Новая ассоциативная структура данных, если быть более точной, но не зависимо.) Много копий будет происходить под капотами.

Я считаю, что вам лучше всего создать бесплатный sh data- структура из размеров существующего. Если вложенные векторы могут иметь разные размеры, код @cfrick пишет (map ... constantly) хорошо. Если все вложенные векторы имеют одинаковый размер, есть более простая альтернатива. Попробуйте найти его и расскажите нам, как оно идет. : -)

2 голосов
/ 16 марта 2020

Поскольку у вас уже есть размеры структуры (это вектор векторов), я думаю, что нет необходимости передавать какие-либо размеры. Таким образом, единственное, что нужно удостовериться, это сохранить векторы (многие инструменты в последовательности поясного ремня используют (ленивые) последовательности).

Использование mapv делает это. Функция для сопоставления может быть (constantly 0). Затем сопоставьте это снова с внешним вектором. Например,

Обычное замыкание:

(mapv (partial mapv (constantly 0)) [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
; → [[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]]

Альтернатива:

Использование Призрак :

(setval [ALL ALL] 0 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
; → [[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]]
1 голос
/ 17 марта 2020

Массивы Clojure являются неизменяемыми, поэтому, если вы хотите работать императивно / изменчиво, вам нужно использовать atom. Рассмотрим следующий код:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(defn new-array
  [M N]
  (vec (for [i (range M)] 
         (vec (for [j (range N)]
                (* i j))))))

(defn set-array-elem
  [arr i j val]
  (assoc-in arr [i j] val))

(defn change-array
  [arr]
  (let [work (atom arr)]
    (doseq [i (range (count @work))]
      (doseq [j (range (count (get @work i)))]
        (swap! work set-array-elem i j
          (* (inc i) (+ 3 j))))) ; set it to an "interesting" value
    @work))

(dotest
  (let [arr1 (new-array 3 5)]
    (is= arr1
      [[0 0 0 0 0]
       [0 1 2 3 4]
       [0 2 4 6 8]])
    (is= (change-array arr1)
      [[3  4  5  6  7]
       [6  8 10 12 14]
       [9 12 15 18 21]])))

Функция set-array-elem возвращает измененную копию входного массива. swap! в change-array вызывает эту функцию и сохраняет вывод в атоме work, заменяя предыдущее неизменное значение. Таким образом, мы постепенно переходим от исходного массива к конечному результату, по одному элементу за раз.

Я понимаю, что это упражнение для обучения. Если вам когда-либо понадобится манипулировать массивами (вложенными векторами), рассмотрите возможность использования tupelo.array или tupelo.array.mutable и сэкономьте много времени на запись (и отладку!)

1 голос
/ 16 марта 2020

Вы можете создать список 0 с помощью repeat:

(repeat 3 0)
; (0 0 0)

Вы можете преобразовать его в вектор с помощью vec:

(vec (repeat 3 0))
; [0 0 0]

Вам просто нужно заменить 3 длиной каждого субвектора:

(mapv #(-> (count %) (repeat 0) vec) [[1] [2 3] [4 5 6]])
; [[0] [0 0] [0 0 0]]
0 голосов
/ 18 марта 2020

Итак, если вы знаете, каковы размеры вашего массива, создайте новый.

(defn make-ary [m n]
  (vec (repeat m (vec (repeat n 0)))))
0 голосов
/ 17 марта 2020

Полагаю, я использовал ассо c - неправильно. Предполагалось использовать recur для реализации asso c -in. Я предполагаю, что именно поэтому я получил несколько экземпляров двумерного вектора вместо одного. Использование recur помогло сделать это.

Спасибо @cfrick @Stefan Kamphausen @Alan Thompson за указание мне правильного направления.

(defn trial [n m]
  (loop [i 0
         j 0
         m m
         ]
    (if (= i n)
      m
      (if (= j (dec n))
        (recur (inc i) 0 (assoc-in m[i j] 0))
        (recur i (inc j) (assoc-in m[i j] 0))
        )
      )
    )
  )

(trial 8 [[6 1 8 8 6 1 8 8][8 4 5 6 6 1 8 8][6 1 8 8 6 1 8 8][3 1 8 9 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8]])

[[0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]]
...