Clojure сжимать вектор - PullRequest
       0

Clojure сжимать вектор

4 голосов
/ 13 октября 2010

Я пытаюсь найти идиоматический способ Clojure для «сжатия» вектора:

(shift-nils-left [:a :b :c :a nil :d nil])
;=> (true [nil nil :a :b :c :a :d])
(shift-nils-left [nil :a])
;=> (false [nil :a])
(shift-nils-left [:a nil])
;=> (true [nil :a])
(shift-nils-left [:a :b])
;=> (false [:a :b])

Другими словами, я хочу переместить все значения nil в левый конец вектора без изменения длины. Логическое значение указывает, произошло ли какое-либо смещение. «Внешняя» структура может быть любой seq, но внутренним результатом должен быть вектор.

Я подозреваю, что функция будет включать filter (для значений nil) и into для добавления к вектору nil s той же длины, что и оригинал, но я не уверен, как уменьшить результат возвращается к исходной длине. Я знаю, как справиться с этой «длинной рукой», но подозреваю, что Clojure сможет сделать это в одну строку.

Я играю за идею написать игрока Bejeweled в качестве упражнения для изучения Clojure.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 13 октября 2010

Я бы написал так:

(ns ...
  (:require [clojure.contrib.seq-utils :as seq-utils]))

(defn compress-vec
  "Returns a list containing a boolean value indicating whether the
  vector was changed, and a vector with all the nils in the given
  vector shifted to the beginning."
  ([v]
     (let [shifted (vec (apply concat (seq-utils/separate nil? v)))]
       (list (not= v shifted)
             shifted))))

Редактировать: итак, так же, как Томас побил меня публикацией, но я бы не использовал flatten на тот случай, если вы в конечном итоге используете какой-тоseqable объект для представления драгоценных камней.

2 голосов
/ 13 октября 2010

Немного более низкоуровневый подход. Он проходит входную последовательность только один раз, а также вектор ненулевых значений один раз. Еще два подхода высокого уровня проходят входную последовательность два раза (для nil? и (complenent nil?)). not= обходит вход в третий раз в худшем случае без смещения.

(defn compress-vec
  [v]
  (let [[shift? nils non-nils]
        (reduce (fn [[shift? nils non-nils] x]
                  (if (nil? x)
                    [(pos? (count non-nils)) (conj nils nil) non-nils]
                    [shift? nils (conj non-nils x)]))
                [false [] []] v)]
    [shift? (into nils non-nils)]))
2 голосов
/ 13 октября 2010

Может быть, так:

(defn shift-nils-left
   "separate nil values" 
    [s] 
    (let [s1 (vec (flatten (clojure.contrib.seq/separate nil? s)))] 
        (list (not (= s s1)) s1)))
1 голос
/ 14 апреля 2011
(def v [1 2 nil 4 5 nil 7 8] )

(apply vector (take 8 (concat (filter identity v) (repeat nil))))

Создает последовательность ненулевых значений в векторе, используя filter, а затем добавляет нули в конец последовательности Это дает значения, которые вы хотите в виде последовательности, а затем преобразует их в вектор. take 8 гарантирует, что вектор имеет правильный размер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...