Я часто виявляю, що використовую лінивий список, коли хочу вектор, і навпаки. Крім того, іноді у мене є вектор карт, коли я дуже хотів набір карт. Чи є якісь допоміжні функції, які допоможуть мені перетворити між цими типами?
Я часто виявляю, що використовую лінивий список, коли хочу вектор, і навпаки. Крім того, іноді у мене є вектор карт, коли я дуже хотів набір карт. Чи є якісь допоміжні функції, які допоможуть мені перетворити між цими типами?
Відповіді:
Не забуваємо, що надійний старий intoдозволяє взяти все, що можна seq(список, вектор, карту, набір, відсортовану карту) та порожній контейнер, який ви хочете заповнити, і помістити intoйого.
(into [] '(1 2 3 4)) ==> [1 2 3 4] "have a lazy list and want a vector"
(into #{} [1 2 3 4]) ==> #{1 2 3 4} "have a vector and want a set"
(into {} #{[1 2] [3 4]}) ==> {3 4, 1 2} "have a set of vectors want a map"
(into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"
into- це обгортка навколо conj, яка є базовою абстракцією для відповідної вставки нових записів у колекцію на основі типу колекції. Принцип, який робить цей потік таким приємним , полягає в тому, що Clojure базується на складаються абстракціях , в даному випадку intoповерх conjзверху колекції та seq.
Наведені вище приклади все одно добре складатимуться, якщо одержувач був переданий під час виконання: оскільки основні абстракції ( seqі conj) реалізовані для всіх колекцій (і багатьох колекцій Java також), тому про вищі абстракції не потрібно турбуватися про безліч спеціальних кутових справ, пов’язаних із даними.
intoвикористання conj, виконуючи, (into '() some-seq)вийде список, який є зворотним до деякого- conjнаступного , оскільки покладається на списки.
intoвикористовуються перехідні процеси (для більшості наступних типів) для кращих характеристик продуктивності, ніж більшість інших засобів перетворення.
vec, setі, як правило into, ваші друзі легко "перетворюють" на інший тип колекції.
Як ви хочете перетворити вектор карт на карту карт? Вам потрібен ключ, чи можете ви використати зразки вводу / очікуваного результату?
Для векторів існує vecфункція
user=> (vec '(1 2 3))
[1 2 3]
Для лінивих послідовностей є lazy-seqфункція
user=> (lazy-seq [1 2 3])
(1 2 3)
Для перетворення в набори існує setфункція
user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}
lazy-seqа не seqпросто додає марну опосередкованість. Якщо ви дійсно хочете повернути щось ненульове, навіть перед порожніми колекціями, там є sequence. lazy-seqє дещо конструкцією низького рівня.
Ще одна відповідь для перетворення зі списку на карту (заради повноти) - звідси :
(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}
Щоб перетворити вектор у список, ви також можете скористатися forтаким чином:
=> (for [i [1 2 3 4]] i)
(1 2 3 4)
Коли ви не хочете маніпулювати даними, просто використовуйте seqна векторі:
=> (seq [1 2 3])
(1 2 3)
forви могли просто зробити(map identity [1 2 3 4])
Немає необхідності перетворювати вектор у список. Clojure буде поводитися з вектором, як зі списком - як з послідовністю - коли потрібна послідовність. Наприклад,
user=> (cons 0 [1 2 3])
(0 1 2 3)
Якщо вам потрібно переконатися, що вектор обробляється як послідовність, оберніть його в seq:
user=> (conj [1 2 3] 0) ; treated as a vector
[1 2 3 0]
user=> (conj (seq [1 2 3]) 0) ; treated as a sequence
(0 1 2 3)
Якщо у вас є вектор карт, і ви хочете набір карт, неважливо, що вектор містить карти. Ви просто перетворюєте вектор у набір, як зазвичай:
user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}