Как преобразовать вектор [1 2 3: a: b: c: A: B: C] в [{: индекс 1: нижний: a: верхний: A} {: индекс 2: нижний: b: верхний: B} {: индекс 3: нижний: c: верхний: C}]? - PullRequest
0 голосов
/ 11 апреля 2019

Я хочу знать, как преобразовать

vector [1 2 3 :a :b :c :A :B :C] 

в

[ {:index 1 :lower :a :upper :A} {:index 2 :lower :b :upper :B} {:index 3 :lower :c :upper :C}  ]  ?

вектор может быть [1 2 3 4: a: b: c: d: A: B: C: D]

или, если нет простого способа, есть ли способ конвертировать

[{:index 1} {:index 2} {:index 3}]  [{:lower :a} {:lower :b} {:lower :c}]   [{:upper :A} {:upper :B} {:upper :C}] 

в

[{:index 1 :lower :a :upper :A} {:index 2 :lower :b :upper :B} {:index 3 :lower :c :upper :C}]

Спасибо!

Ответы [ 4 ]

1 голос
/ 12 апреля 2019
(let [ks [:index :lower :upper]
      xs [1 2 3 :a :b :c :A :B :C]]
  (->> xs
       (partition (/ (count xs) (count ks)))
       (apply map vector)
       (mapv zipmap (repeat ks))))

Как это работает:

Сначала мы partition вектор по count:

(partition (/ (count xs) (count ks)) xs)=> ((1 2 3) (:a :b :c) (:A :B :C))

Затем транспонируем матрицу:

(apply map vector *1)=> ([1 :a :A] [2 :b :B] [3 :c :C])

Наконец zipmap с предоставленными ключами для каждой строки:

(mapv zipmap (repeat ks) *1)=> [{:index 1, :lower :a, :upper :A} {:index 2, :lower :b, :upper :B} {:index 3, :lower :c, :upper :C}]

1 голос
/ 11 апреля 2019

Итак, в общем, когда я сталкиваюсь с такой проблемой, я бы пошел вверх по течению и исправил формат ввода. Вектор, который является объединением произвольных частей, не имеет никакого смысла. Ради ответа, давайте предположим, что это невозможно.

Сначала мы определим вспомогательную функцию для создания карт результатов:

(defn make-result [i l u]
    {:index i :lower l :upper u})

Тогда нам просто нужно отобразить эту функцию на три подпоследовательности:

(defn input->output [i]
    (apply map make-result (partition (/ (count i) 3) i)))

Нам нужно использовать apply, так как мы генерируем последовательность подпоследовательностей, которые мы хотим использовать в качестве параметров для map (напомним, что функция arity должна соответствовать количеству последовательностей, которые вы передаете map - что удобно для нашего помощника).

Это будет работать для обоих векторов, указанных выше.

(input->output [1 2 3 :a :b :c :A :B :C])
({:index 1, :lower :a, :upper :A} {:index 2, :lower :b, :upper :B} {:index 3, :lower :c, :upper :C})
(input->output [1 2 3 4 :a :b :c :d :A :B :C :D])
({:index 1, :lower :a, :upper :A} {:index 2, :lower :b, :upper :B} {:index 3, :lower :c, :upper :C} {:index 4, :lower :d, :upper :D})

Поведение, если вектор находится в другом формате, может удивить или разочаровать - возможно, требуется некоторая проверка входных данных.

0 голосов
/ 11 апреля 2019

Я не эксперт по уловкам, но, возможно, это поможет:

; your data
(def x [1 2 3 :a :b :c :A :B :C])

; resolve symbols and numbers to strings
(def xa (map (fn [e] (if (keyword? e) (name e) (str e))) x))


; split into three sequences and zip this lists together
(let [xan (filter (fn [e] (not (empty? (re-matches #"[0-9]" e)))) xa)
     xaa (filter (fn [e] (not (empty? (re-matches #"[a-z]" e)))) xa)
     xaA (filter (fn [e] (not (empty? (re-matches #"[A-Z]" e)))) xa)]
     (map-indexed (fn [i e] {:index e :lower (nth xaa i) :upper (nth xaA i)}) xan )) 

Вы просто строите три последовательности, перебираете любую из них и используете индекс для доступа к соответствующим элементам из других.

0 голосов
/ 11 апреля 2019

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

(def items [[{:index 1}  {:index 2}  {:index 3}]
            [{:lower :a} {:lower :b} {:lower :c}]
            [{:upper :A} {:upper :B} {:upper :C}]])

тогда вы можете использовать следующее:

(apply map merge items)
;; returns ({:index 1, :lower :a, :upper :A} {:index 2, :lower :b, :upper :B} {:index 3, :lower :c, :upper :C})

Это работает с помощью функции map для merge отдельных хеш-карт в 3 коллекциях. Сначала сливаются первые элементы каждой коллекции, в результате чего получается элемент {:index 1, :lower :a, :upper :A}, затем сливаются вторые элементы каждой коллекции и т. Д.

Поскольку аргументы map merge являются коллекцией, вам необходимо использовать apply для предоставления аргументов map.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...