Группировать последовательность bools в clojure? - PullRequest
3 голосов
/ 27 марта 2011

Я хотел бы преобразовать следующую последовательность:

(def boollist [true false false false true false true])

На следующее:

[[true] [false false false true] [false true]]

Мой код приводит к переполнению стека:

(defn sep [boollst]
  (loop [lst boollst
         separated [[]]
         [left right] (take 2 lst)]
    (if (nil? left) separated)
    (recur (next lst) 
           (if (false? left)
             (conj (last separated) left)
             (conj separated [left]))
           (take 2 (next lst)))))

Есть ли элегантный способ изменить это?

Ответы [ 4 ]

5 голосов
/ 27 марта 2011

Вероятно, есть гораздо более элегантный способ, но вот что я придумал:

(defn f 
  ([xs] (f xs [] []))
  ([[x & xs :as all] acc a]  
     (if (seq all)
       (if x
         (recur xs [] (conj a (conj acc x)))
         (recur xs (conj acc x) a))
       a)))

Он просто пересекает последовательность, отслеживая текущий вектор ложностей, и до сих пор является большим аккумулятором всего.

4 голосов
/ 28 марта 2011

Короткое, «умное» решение будет следующим:

(defn sep [lst]
  (let [x (partition-by identity lst)]
    (filter last (map concat (cons [] x) x))))

Проблема «переполнения стека» связана с философией Clojure, касающейся рекурсии, и ее легко избежать при правильном подходе.Вы должны всегда реализовывать эти типы функций * ленивым способом: если вы не можете найти хитрость для решения проблемы с использованием библиотечных функций, как я делал выше, вы должны использовать «lazy-seq» для общего решения (например, pmjordan)сделал) как объяснено здесь: http://clojure.org/lazy

* Функции, которые формируют список и возвращают список как результат.(Если возвращается нечто иное, чем список, идиоматическое решение состоит в том, чтобы использовать «recur» и аккумулятор, как показано в примере dfan, который в этом случае я бы не назвал идиоматическим.)

2 голосов
/ 28 марта 2011

Вот версия, которая использует ленивую оценку и, возможно, немного более читабельна:

(defn f [bools]
  (when-not (empty? bools)
    (let
      [[l & r] bools
       [lr rr] (split-with false? r)]
      (lazy-seq (cons
        (cons l lr)
        (f rr))))))

Она не возвращает векторы, поэтому, если это требование, вам нужно вручную передать результат concatсамой функции до vec, что сводит на нет преимущество использования ленивых вычислений.

0 голосов
/ 28 марта 2011

Ошибка переполнения стека из-за того, что ваш recur находится за пределами if.Вы оцениваете форму if для побочных эффектов , затем безоговорочно повторяете(не стесняйтесь редактировать для формата, я не на реальной клавиатуре).

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