У Clojure існує простий спосіб перетворення між типами списків?


92

Я часто виявляю, що використовую лінивий список, коли хочу вектор, і навпаки. Крім того, іноді у мене є вектор карт, коли я дуже хотів набір карт. Чи є якісь допоміжні функції, які допоможуть мені перетворити між цими типами?

Відповіді:


146

Не забуваємо, що надійний старий 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 також), тому про вищі абстракції не потрібно турбуватися про безліч спеціальних кутових справ, пов’язаних із даними.


3
+1 для в ... варто зазначити, що він також працює з непорожніми оригінальними контейнерами (тобто, коли ви хочете додати до колекції)
mikera

11
Варто також зазначити, що оскільки intoвикористання conj, виконуючи, (into '() some-seq)вийде список, який є зворотним до деякого- conjнаступного , оскільки покладається на списки.
Чак,

Варто зазначити, що intoвикористовуються перехідні процеси (для більшості наступних типів) для кращих характеристик продуктивності, ніж більшість інших засобів перетворення.
Джарред Хамфрі,

І зараз це працює з перетворювачами, яких на момент написання цієї відповіді не існувало (я не знаю, чи перехідні фактори теж мали місце) (Ця відповідь досить стара, щоб записатися до дитячого садка)
Артур Ульфельдт,

33

vec, setі, як правило into, ваші друзі легко "перетворюють" на інший тип колекції.

Як ви хочете перетворити вектор карт на карту карт? Вам потрібен ключ, чи можете ви використати зразки вводу / очікуваного результату?


Вибачте, я мав на увазі набір карт .. Я змінив питання зараз
appshare.co

22

Для векторів існує 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}}

4
Коли у вас щось не ледаче дзвонить, lazy-seqа не seqпросто додає марну опосередкованість. Якщо ви дійсно хочете повернути щось ненульове, навіть перед порожніми колекціями, там є sequence. lazy-seqє дещо конструкцією низького рівня.
cgrand


9

Щоб перетворити вектор у список, ви також можете скористатися 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])
siltalau

7

Немає необхідності перетворювати вектор у список. 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}}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.