Clojure lista de partições de strings, acumulando o resultado

Sinto muito pela falta de precisão no título, mas pode ilustrar minha falta de experiência com clojure.

Eu estou tentando tomar uma lista grande de seqüências de caracteres e converter essa lista em outra lista de seqüências de caracteres, concatenando como eu vá até que o acumulador é menor que algum comprimento.

Por exemplo, se eu tiver

[ "a" "bc" "def" "ghij" ]

and my max string length is 4, I would walk down the list, accumulating the concat, until my accumulation len > 4, and then start the accumulator from scratch. My result would look like:

[ "abc" "def" "ghij" ]

Eu não consigo encontrar o encantamento adequado para partition-by , e isso está me deixando um pouco louco. Eu tenho tentado fazer do meu acumulador um atom (mas não consigo descobrir onde reinicializar! ), mas além disso, eu não consigo ver onde/como manter o controle da minha string acumulada.

Agradeço antecipadamente a qualquer um que tenha piedade de mim.

1
Houve alguma incerteza quanto às suas necessidades exatas. Você poderia, por favor, olhar para os testes de unidade incluídos na minha resposta e verificar que é o comportamento que você estava procurando? Obrigado.
adicionado o autor Alan Thompson, fonte
Houve alguma incerteza quanto às suas necessidades exatas. Você poderia, por favor, olhar para os testes de unidade incluídos na minha resposta e verificar que é o comportamento que você estava procurando? Obrigado.
adicionado o autor Alan Thompson, fonte
Obrigado a todos os respondentes - estou usando todas as sugestões como uma experiência de aprendizado e aceito uma resposta quando/se eu entender. Obrigado novamente!
adicionado o autor Hoopes, fonte

7 Respostas

Aqui está como eu faria:

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

(def bound 4)

(defn catter [strings-in]
  (loop [merged-strs    []
         curr-merge     (first strings-in)
         remaining-strs (rest strings-in)]
   ;(newline) (spyx [merged-strs curr-merge remaining-strs])
    (if (empty? remaining-strs)
      (conj merged-strs curr-merge)
      (let          ; try using 'let-spy' instead
        [new-str   (first remaining-strs)
         new-merge (str curr-merge new-str)]
        (if (< (count new-merge) bound)
          (recur merged-strs new-merge (rest remaining-strs))
          (recur (conj merged-strs curr-merge) new-str (rest remaining-strs)))))))

(dotest
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "def" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "b" "c" "def" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "b" "c" "d" "ef" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "d" "ef" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "d" "e" "f" "ghij"]) )

  (is=  ["abc" "def" "gh" "ij"]  (catter ["abc" "d" "e" "f" "gh" "ij"]) )
  (is=  ["abc" "def" "ghi" "j"]  (catter ["abc" "d" "e" "f" "ghi" "j"]) )

  (is=  ["abcdef" "ghi" "j"]     (catter ["abcdef" "ghi" "j"]) )
  (is=  ["abcdef" "ghi" "j"]     (catter ["abcdef" "g" "h" "i" "j"]) )
)

Você precisará adicionar [tupelo "0.9.71"] às dependências do projeto.


Atualizar:

Se você usuário espião e deixar-espião , você pode ver o processo que o algoritmo usa para chegar ao resultado. Por exemplo:

(catter ["a" "b" "c" "d" "ef" "ghij"]) )   =>     ["abc" "def" "ghij"]     

-----------------------------------------------------------------------------
strings-in => ["a" "b" "c" "d" "ef" "ghij"]

[merged-strs curr-merge remaining-strs] => [[] "a" ("b" "c" "d" "ef" "ghij")]
new-str => "b"
new-merge => "ab"

[merged-strs curr-merge remaining-strs] => [[] "ab" ("c" "d" "ef" "ghij")]
new-str => "c"
new-merge => "abc"

[merged-strs curr-merge remaining-strs] => [[] "abc" ("d" "ef" "ghij")]
new-str => "d"
new-merge => "abcd"

[merged-strs curr-merge remaining-strs] => [["abc"] "d" ("ef" "ghij")]
new-str => "ef"
new-merge => "def"

[merged-strs curr-merge remaining-strs] => [["abc"] "def" ("ghij")]
new-str => "ghij"
new-merge => "defghij"

[merged-strs curr-merge remaining-strs] => [["abc" "def"] "ghij" ()]

Ran 2 tests containing 10 assertions.
0 failures, 0 errors.
4
adicionado

Aqui está como eu faria:

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

(def bound 4)

(defn catter [strings-in]
  (loop [merged-strs    []
         curr-merge     (first strings-in)
         remaining-strs (rest strings-in)]
   ;(newline) (spyx [merged-strs curr-merge remaining-strs])
    (if (empty? remaining-strs)
      (conj merged-strs curr-merge)
      (let          ; try using 'let-spy' instead
        [new-str   (first remaining-strs)
         new-merge (str curr-merge new-str)]
        (if (< (count new-merge) bound)
          (recur merged-strs new-merge (rest remaining-strs))
          (recur (conj merged-strs curr-merge) new-str (rest remaining-strs)))))))

(dotest
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "def" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "b" "c" "def" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "b" "c" "d" "ef" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "d" "ef" "ghij"]) )
  (is=  ["abc" "def" "ghij"]     (catter ["a" "bc" "d" "e" "f" "ghij"]) )

  (is=  ["abc" "def" "gh" "ij"]  (catter ["abc" "d" "e" "f" "gh" "ij"]) )
  (is=  ["abc" "def" "ghi" "j"]  (catter ["abc" "d" "e" "f" "ghi" "j"]) )

  (is=  ["abcdef" "ghi" "j"]     (catter ["abcdef" "ghi" "j"]) )
  (is=  ["abcdef" "ghi" "j"]     (catter ["abcdef" "g" "h" "i" "j"]) )
)

Você precisará adicionar [tupelo "0.9.71"] às dependências do projeto.


Atualizar:

Se você usuário espião e deixar-espião , você pode ver o processo que o algoritmo usa para chegar ao resultado. Por exemplo:

(catter ["a" "b" "c" "d" "ef" "ghij"]) )   =>     ["abc" "def" "ghij"]     

-----------------------------------------------------------------------------
strings-in => ["a" "b" "c" "d" "ef" "ghij"]

[merged-strs curr-merge remaining-strs] => [[] "a" ("b" "c" "d" "ef" "ghij")]
new-str => "b"
new-merge => "ab"

[merged-strs curr-merge remaining-strs] => [[] "ab" ("c" "d" "ef" "ghij")]
new-str => "c"
new-merge => "abc"

[merged-strs curr-merge remaining-strs] => [[] "abc" ("d" "ef" "ghij")]
new-str => "d"
new-merge => "abcd"

[merged-strs curr-merge remaining-strs] => [["abc"] "d" ("ef" "ghij")]
new-str => "ef"
new-merge => "def"

[merged-strs curr-merge remaining-strs] => [["abc"] "def" ("ghij")]
new-str => "ghij"
new-merge => "defghij"

[merged-strs curr-merge remaining-strs] => [["abc" "def"] "ghij" ()]

Ran 2 tests containing 10 assertions.
0 failures, 0 errors.
4
adicionado
(defn catsize [limit strs]
  (reduce (fn [res s]
              (let [base (peek res)]
                (if (> (+ (.length ^String base) (.length ^String s)) limit)
                  (conj res s)
                  (conj (pop res) (str base s)))))
          (if (seq strs) [(first strs)] [])
          (rest strs)))
2
adicionado
(defn catsize [limit strs]
  (reduce (fn [res s]
              (let [base (peek res)]
                (if (> (+ (.length ^String base) (.length ^String s)) limit)
                  (conj res s)
                  (conj (pop res) (str base s)))))
          (if (seq strs) [(first strs)] [])
          (rest strs)))
2
adicionado

Aqui está minha opinião sobre isso:

(defn collapse [maxlen xs]
  (let [concats (take-while #(< (count %) maxlen) (reductions str xs))]
    (cons (last concats) (drop (count concats) xs))))
(collapse 4 ["a" "bc" "def" "ghij"])
;; => ("abc" "def" "ghij")
2
adicionado
a abordagem está correta, mas funciona apenas no caso de a subsequência estar no início da entrada. Falha por (recolher 4 ["a" "bc" "def" "ghij" "z" "xc" "vbn"]) => ("abc" "def" " ghij "" z "" xc "" vbn ") , ou (colapso 4 [" asdf "" a "" bc "" def "" ghij "]) => (nil "asdf" "a" "bc" "def" "ghij") .. Isso deve ser corrigido de alguma forma)))
adicionado o autor leetwinski, fonte

Aqui está minha opinião sobre isso:

(defn collapse [maxlen xs]
  (let [concats (take-while #(< (count %) maxlen) (reductions str xs))]
    (cons (last concats) (drop (count concats) xs))))
(collapse 4 ["a" "bc" "def" "ghij"])
;; => ("abc" "def" "ghij")
2
adicionado
a abordagem está correta, mas funciona apenas no caso de a subsequência estar no início da entrada. Falha por (recolher 4 ["a" "bc" "def" "ghij" "z" "xc" "vbn"]) => ("abc" "def" " ghij "" z "" xc "" vbn ") , ou (colapso 4 [" asdf "" a "" bc "" def "" ghij "]) => (nil "asdf" "a" "bc" "def" "ghij") .. Isso deve ser corrigido de alguma forma)))
adicionado o autor leetwinski, fonte

Isso fica bem perto. Não tenho certeza porque você tem j no final da string final.

(sequence
 (comp
  (mapcat seq)
  (partition-all 3)
  (map clojure.string/join))
 ["a" "bc" "def" "ghij"]) => ("abc" "def" "ghi" "j")
1
adicionado