concat
возвращает ленивую последовательность.Вы можете привести его к вектору, используя:
(vec (concat ...))
Вот полный код с тестом:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn draw-random-card
[cards]
(let [card (rand-nth cards)
index (.indexOf cards card)]
{:drawn-card card :remaining-cards (vec (concat (subvec cards 0 index)
(subvec cards (inc index))))}))
(def full-deck ["Ace" 2 3 4 5 6 7 8 9 10 "Jack" "Queen" "King"])
(dotest
(let [first-draw (draw-random-card full-deck)
first-card (:drawn-card first-draw)
second-draw (draw-random-card (:remaining-cards first-draw))
second-card (:drawn-card second-draw)
remaining-deck (:remaining-cards second-draw)]
(println "First card: " first-card)
(println "Second card: " second-card)
(println "Remaining deck:" remaining-deck))
)
и результат:
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
Testing tst.demo.core
First card: Queen
Second card: King
Remaining deck: [Ace 2 3 4 5 6 7 8 9 10 Jack]
Обновление:
Точнее говоря, проблема заключалась в вызове subvec
во 2-й итерации вашего кода.Вот пример:
(dotest
(let [vals (vec (range 10)) ; a vector
s1 (subvec vals 2 4) ; so `subvec` works
s2 (subvec vals 6) ; and again
lazies (concat s1 s2)] ; creates a lazy sez
(is= [2 3] (spyxx s1))
(is= [6 7 8 9] (spyxx s2))
(is= [2 3 6 7 8 9] (spyxx lazies))
(throws? (subvec lazies 0 2)))) ; ***** can't call `subvec` on a non-vector (lazy sequence here) *****
с результатом:
s1 => <#clojure.lang.APersistentVector$SubVector [2 3]>
s2 => <#clojure.lang.APersistentVector$SubVector [6 7 8 9]>
lazies => <#clojure.lang.LazySeq (2 3 6 7 8 9)>
, поэтому, приведя вывод concat
к вектору, вызов к subvec
завершится в следующий разчерез функцию.
Итак, задним числом, лучшим решением было бы привести ввод к вектору, например так:
(let [cards (vec cards)
card (rand-nth cards)
index (.indexOf cards card)]
{:drawn-card card
:remaining-cards (vec (concat (subvec cards 0 index)
(subvec cards (inc index))))}))
Update # 2
Если вы не хотите принудительно вводить данные в vector
, вы можете использовать функцию .subList()
через взаимодействие Java:
(dotest
(spyxx (.subList (concat (range 5) (range 10 15)) 5 10))
(spyxx (.subList (range 10) 2 5))
(spyxx (.subList (vec (range 10)) 2 5))
(spyxx (subvec (vec (range 10)) 2 5))
(throws? (subvec (range 10) 2 5))) ; *** not allowed ***
с результатом
(.subList (concat (range 5) (range 10 15)) 5 10)
=> <#java.util.ArrayList$SubList [10 11 12 13 14]>
(.subList (range 10) 2 5)
=> <#java.util.Collections$UnmodifiableRandomAccessList [2 3 4]>
(.subList (vec (range 10)) 2 5)
=> <#clojure.lang.APersistentVector$SubVector [2 3 4]>
(subvec (vec (range 10)) 2 5)
=> <#clojure.lang.APersistentVector$SubVector [2 3 4]>