clojure переименовывает ключи во вложенной структуре - PullRequest
8 голосов
/ 20 октября 2011

Предположим, у меня есть вложенная структура, примерно такая:

{:data1 
    {:categories [
        {:name "abc" :id 234 :desc "whatever"} 
        {:name "def" :id 456 :desc "nothing"}]
    }
  :data2 {...}
  :data3 {...}
}

И мне нужно преобразовать имена ключей в картах.Я могу преобразовать ключи верхнего уровня следующим образом:

(rename-keys mymap {:data1 :d1})

Но я не уверен, как переименовать ключи, более глубоко вложенные в структуру данных (например, я хочу переименовать поле: desc в: description).

Я почти уверен, что ответ - молния, но не могу понять, как это сделать, или есть более простой способ.

Ответы [ 3 ]

8 голосов
/ 20 октября 2011

То же, что и решение Брайана Карпера, за исключением того, что пространство имен прогулки уже имеет специальную функцию для этой цели. Все ключи на всех уровнях изменены, независимо от того, вложены ли они в какую-либо коллекцию или последовательность.

(:use 'clojure.walk)

(def x
  {:data1
   {:categories
    [{:desc "whatever", :name "abc", :id 234}
     {:desc "nothing", :name "def", :id 456}]},
   :data2
   {:categories
    [{:desc "whatever", :name "abc", :id 234}
     {:desc "nothing", :name "def", :id 456}]}})

(postwalk-replace {:desc :something} x)

{:data1
 {:categories
  [{:something "whatever", :name "abc", :id 234}
   {:something "nothing", :name "def", :id 456}]},
 :data2
 {:categories
  [{:something "whatever", :name "abc", :id 234}
   {:something "nothing", :name "def", :id 456}]}}
6 голосов
/ 20 октября 2011

postwalk в целом довольно тяжелый кувалдой, хотя из вашего первоначального вопроса видно, что он вам может понадобиться. Во многих случаях вы можете выполнять обновления во вложенной структуре с помощью update-in:

user> (let [m {:foo {:deep {:bar 1 :baz 2}}}]
        (update-in m [:foo :deep] clojure.set/rename-keys {:baz :periwinkle}))
{:foo {:deep {:periwinkle 2, :bar 1}}}
3 голосов
/ 20 октября 2011

Если вы хотите переименовать все ключи :desc независимо от того, на каком уровне вложенности они находятся, это может сработать. Если вы хотите переименовать ключи :desc только на определенном уровне вложенности, вам понадобится что-то более сложное.

Это работает только потому, что clojure.set/rename-keys в настоящее время ничего не делает (возвращает свой первый аргумент без изменений), если его первый аргумент не является картой.

user> (require '[clojure [set :as set] [walk :as walk]])
nil

user> (def x {:data1
              {:categories
               [{:desc "whatever", :name "abc", :id 234}
                {:desc "nothing", :name "def", :id 456}]},
              :data2
              {:categories
               [{:desc "whatever", :name "abc", :id 234}
                {:desc "nothing", :name "def", :id 456}]}})
#'user/x

user> (walk/postwalk #(set/rename-keys % {:desc :description :id :ID}) x)
{:data1
 {:categories
  [{:name "abc", :ID 234, :description "whatever"}
   {:name "def", :ID 456, :description "nothing"}]},
 :data2
 {:categories
  [{:name "abc", :ID 234, :description "whatever"}
   {:name "def", :ID 456, :description "nothing"}]}}
nil
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...