Clojure에서 벡터 앞에 추가하는 관용적 방법은 무엇입니까?
목록에 추가하는 것은 쉽습니다.
user=> (conj '(:bar :baz) :foo)
(:foo :bar :baz)
벡터에 추가하는 것은 쉽습니다.
user=> (conj [:bar :baz] :foo)
[:bar :baz :foo]
벡터를 다시 가져 오는 동안 어떻게 (관상 적으로) 벡터 앞에 추가합니까? 벡터가 아닌 seq를 반환하므로 작동하지 않습니다.
user=> (cons :foo [:bar :baz])
(:foo :bar :baz)
이것은 추악합니다 (IMVHO) :
user=> (apply vector (cons :foo [:bar :baz]))
[:foo :bar :baz]
참고 : 기본적으로 추가하고 앞에 추가 할 수있는 데이터 구조를 원합니다. 큰 목록에 추가하면 성능이 크게 저하되므로 벡터를 생각했습니다.
벡터는 앞에 붙일 수 없습니다. 앞에 O (n) 만 추가됩니다.
user=> (into [:foo] [:bar :baz])
[:foo :bar :baz]
당신이 원하는 것은 손가락 나무 일 가능성이 큽니다 .
나는이 질문이 오래되었다는 것을 알고 있지만, 아무도 차이 목록에 대해 아무 말도하지 않았고, 당신이 정말로 추가하고 앞에 붙일 수있는 것을 원한다고 말했기 때문에 차이 목록이 도움이 될 것 같습니다. Clojure에서는 인기가 없어 보이지만 구현하기가 매우 쉽고 핑거 트리보다 훨씬 덜 복잡하기 때문에 지금 막 차이 목록 라이브러리를 만들었습니다. O (1) 시간에 연결됩니다 (앞에 추가 또는 추가). 차이 목록을 목록으로 다시 변환하면 O (n) 비용이 발생합니다. 이는 많은 연결을 수행하는 경우 좋은 절충안입니다. 연결을 많이하지 않는다면 목록에 충실하세요. 그렇죠? :)
이 작은 라이브러리의 기능은 다음과 같습니다.
dl : 차이 목록은 실제로 자신의 내용을 인수와 연결하고 결과 목록을 반환하는 함수입니다. 차이 목록을 생성 할 때마다 데이터 구조처럼 작동하는 작은 함수를 생성합니다.
dlempty : 차이 목록은 그 내용을 인수에 연결하기 만하 므로 빈 차이 목록은 식별 함수와 동일합니다.
undl : 차이 목록이하는 일 때문에 nil로 호출하는 것만으로 차이 목록을 일반 목록으로 변환 할 수 있으므로이 함수는 실제로 필요하지 않습니다. 그것은 단지 편의를위한 것입니다.
dlcons : 항목을 목록의 맨 앞에 표시합니다 . 완전히 필요하지는 않지만 consing은 충분히 일반적인 작업이며 여기에있는 모든 기능과 마찬가지로 한 줄로만 처리됩니다.
dlappend : 두 개의 차이점 목록을 연결합니다. 그 정의가 가장 재미 있다고 생각합니다. 확인해보세요! :)
이제 여기에 작은 라이브러리가 있습니다. O (1) 추가 / 앞에 데이터 구조를 제공하는 5 개의 한 줄 함수입니다. 나쁘지 않아요? 아, Lambda Calculus의 아름다움 ...
(defn dl
"Return a difference list for a list"
[l]
(fn [x] (concat l x)))
; Return an empty difference list
(def dlempty identity)
(defn undl
"Return a list for a difference list (just call the difference list with nil)"
[aDl]
(aDl nil))
(defn dlcons
"Cons an item onto a difference list"
[item aDl]
(fn [x] (cons item (aDl x))))
(defn dlappend
"Append two difference lists"
[dl1 dl2]
(fn [x] (dl1 (dl2 x))))
다음과 같이 작동하는 것을 볼 수 있습니다.
(undl (dlappend (dl '(1 2 3)) (dl '(4 5 6))))
다음을 반환합니다.
(1 2 3 4 5 6)
이것은 또한 같은 것을 반환합니다.
((dl '(1 2 3)) '(4 5 6))
차이점 목록으로 재미있게 보내십시오!
최신 정보
이해하기 더 어려울 수 있지만 더 나은 정의는 다음과 같습니다.
(defn dl [& elements] (fn [x] (concat elements x)))
(defn dl-un [l] (l nil))
(defn dl-concat [& lists] (fn [x] ((apply comp lists) x)))
이렇게하면 다음과 같이 말할 수 있습니다.
(dl-un (dl-concat (dl 1) (dl 2 3) (dl) (dl 4)))
어느 것이 돌아올 것인가
(1 2 3 4)
사용자 optevo가 finger trees 대답 아래의 주석에서 말했듯이 RRB-tree를 구현 하는 clojure / core.rrb-vector lib를 사용할 수 있습니다 .
RRB-Trees build upon Clojure's PersistentVectors, adding logarithmic time concatenation and slicing. ClojureScript is supported with the same API except for the absence of the
vector-of
function.
I decided to post this as a separate answer, because I think this library deserves that. It supports ClojureScript and it's maintained by Michał Marczyk, who is fairly known within the Clojure community for his work on implementing various data structures.
If you don't fear quasiquoting, this solution is actually pretty elegant (for some definitions of 'elegant'):
> `[~:foo ~@[:bar :baz]]
[:foo :bar :baz]
I actually use this on occasion in real code, since the declarative syntax makes it pretty readable IMHO.
I would suggest using the convenience features built into the Tupelo Library. For example:
(append [1 2] 3 ) ;=> [1 2 3 ]
(append [1 2] 3 4) ;=> [1 2 3 4]
(prepend 3 [2 1]) ;=> [ 3 2 1]
(prepend 4 3 [2 1]) ;=> [4 3 2 1]
by comparison, with raw Clojure it is easy to make a mistake:
; Add to the end
(concat [1 2] 3) ;=> IllegalArgumentException
(cons [1 2] 3) ;=> IllegalArgumentException
(conj [1 2] 3) ;=> [1 2 3]
(conj [1 2] 3 4) ;=> [1 2 3 4]
; Add to the beginning
(conj 1 [2 3] ) ;=> ClassCastException
(concat 1 [2 3] ) ;=> IllegalArgumentException
(cons 1 [2 3] ) ;=> (1 2 3)
(cons 1 2 [3 4] ) ;=> ArityException
ReferenceURL : https://stackoverflow.com/questions/4095714/what-is-the-idiomatic-way-to-prepend-to-a-vector-in-clojure
'programing' 카테고리의 다른 글
스택 가비지가 Java에서 수집됩니까? (0) | 2021.01.14 |
---|---|
"불법 한 정의 시작"을주는 Scala (0) | 2021.01.14 |
개발 환경에서 Rails 3로 메일 보내기 (0) | 2021.01.14 |
스칼라의 foreach 대 표현식 (0) | 2021.01.14 |
JAXB : 모든 요소에 네임 스페이스 접두사 필요 (0) | 2021.01.14 |