Я часто виявляю, що використовую лінивий список, коли хочу вектор, і навпаки. Крім того, іноді у мене є вектор карт, коли я дуже хотів набір карт. Чи є якісь допоміжні функції, які допоможуть мені перетворити між цими типами?
Я часто виявляю, що використовую лінивий список, коли хочу вектор, і навпаки. Крім того, іноді у мене є вектор карт, коли я дуже хотів набір карт. Чи є якісь допоміжні функції, які допоможуть мені перетворити між цими типами?
Відповіді:
Не забуваємо, що надійний старий 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}}