Элегантный способ объединить списки и элементы в вектор - PullRequest
2 голосов
/ 12 февраля 2020

Есть ли более краткий и / или элегантный способ express последней строки в let.

(let [a ... ; int
      b ... ; int
      xs ... ; list
      y ... ; int
      z ... ; int
      ]
  (into [a b] cat [xs [y z]]))

Результатом должен быть вектор. Выражение выше выглядит довольно сложным для простой задачи, которую оно выполняет. В Python это будет [a, b] + xs + [y,z], что лучше отражает сходство двух операций добавления. Более длинный вариант, который бы охватил это сходство:

(into [] cat [[a b] xs [yz]])

Мои попытки использовать concat кажутся многословными, но, возможно, более читабельными?

(vec (concat [a b] xs [y z]))

Ответы [ 3 ]

6 голосов
/ 12 февраля 2020

в / cat определенно будет самым популярным подходом. Если вы умираете за краткость, вместо этого вы можете использовать синтаксис-цитату, мощный инструмент для создания списков:

`[~a ~b ~@xs ~y ~z]

Это очень выразительно и работает, но, безусловно, будет медленнее: оно предназначено в основном для использовать во время компиляции с небольшими входами. Хотя накладные расходы довольно малы; Вы можете увидеть, к какому коду это будет расширяться, заключив его в кавычки:

user=> '`[~a ~b ~@xs ~y ~z]
(apply vector 
       (seq (concat (list a)
                    (list b)
                    xs
                    (list y)
                    (list z))))

Я отредактировал вывод, чтобы сделать его более читабельным, удалив префикс clojure.core/ и добавив пробел, но семантически это то, что REPL напечатано.

1 голос
/ 13 февраля 2020

Вау! Сколько лет прошло, и я так и не понял, преобразователь cat был добавлен в язык. Сначала я подумал, что у вас есть какой-то Python -секретный псевдокод.

Конкретный пример:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))  ; <= *** many helper functions! ***

(dotest
  (let [a  1 ; int
        b  2 ; int
        xs [:x1 :x2 :x3] ; list
        y  25 ; int
        z  26 ; int
        ]
    (spyx (into [a b] cat [xs [y z]]))))

, который печатает:

(into [a b] cat [xs [y z]]) => [1 2 :x1 :x2 :x3 25 26]

Re your вопрос, для маленьких sh размеров concat кажется вполне хорошим ответом:

(concat [a b] xs [y z]) => (1 2 :x1 :x2 :x3 25 26)  ; A lazy sequence

, хотя вы должны знать о Тикающей бомбе замедленного действия для больших последовательностей. Если вам нужна простота и вам не нужна лень, я написал функцию glue в библиотеке Tupelo Clojure :

; Glue together like collections:
(is (= (glue [ 1 2] '(3 4) [ 5 6] )       [ 1 2 3 4 5 6 ]  ))   ; all sequential (vectors & lists)
(is (= (glue {:a 1} {:b 2} {:c 3} )       {:a 1 :c 3 :b 2} ))   ; all maps
(is (= (glue #{1 2} #{3 4} #{6 5} )      #{ 1 2 6 5 3 4 }  ))   ; all sets
(is (= (glue "I" " like " \a " nap!" )   "I like a nap!"   ))   ; all text (strings & chars)

; If you want to convert to a sorted set or map, just put an empty one first:
(is (= (glue (sorted-map) {:a 1} {:b 2} {:c 3})   {:a 1 :b 2 :c 3} ))
(is (= (glue (sorted-set) #{1 2} #{3 4} #{6 5})  #{ 1 2 3 4 5 6  } ))

Другой ответ похож на идею использования syntax-quote, используя -> vector и unwrap :

(->vector 1 2 3 4 5 6 7 8 9)             =>  [1 2 3 4 5 6 7 8 9]
(->vector 1 (unwrap [2 3 4 5 6 7 8]) 9)  =>  [1 2 3 4 5 6 7 8 9]

Это также будет работать рекурсивно для вложенных вызовов unwrap:

(->vector 1 (unwrap [2 3 (unwrap [4 5 6]) 7 8]) 9)  =>  [1 2 3 4 5 6 7 8 9]

Если скалярные значения находятся только в начале или в конце, я бы предложил с использованием prepend и append:

(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]

Конечно, если вам не нужно сохранять любая вложенная структура в 5 вещах, которые вы комбинируете, возможно, Большой Кувалда (тм) является самым простым:

(flatten [[a b] xs [y z]]) => (1 2 :x1 :x2 :x3 25 26)

Как всегда, не забудьте для изучения Clojure CheatSheet!

1 голос
/ 12 февраля 2020

Зависит от того, что у вас ... с. Может быть, вы бы предпочли перенести часть многословия на let? Иногда сложные линии являются признаком того, что функциям, обеспечивающим ваши входные данные, могут помочь меньшие промежуточные функции. Например, здесь у вас есть функции get-ab и get-yz, которые возвращают [a b] и [y z] соответственно.

(let [ab (get-ab) ; list
      xs ... ; list
      yz ... (get-yz)] ; list
  (into [] cat [ab xs yz]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...