Что касается вашего желаемого результата, последняя карта, которую вы разместили, не делает то, что вы думаете, что делает. На этой карте:
{"tiger" ("fur" "yellow & black stripes") ("weight" "150") ("home" "India")}
Это не карта с одним ключом и тремя значениями, это карта с двумя ключами ("tiger"
и ("weight" "150")
) и двумя значениями.
Следующее не отвечает на ваш вопрос напрямую, но говорит о идиоматическом Clojure. В Clojure вам будет легче, если вы выберете правильные структуры данных для текущей работы.
Для исходных данных вам, вероятно, следует использовать векторы вместо списков, если у вас нет веских оснований для использования списков. Векторы работают лучше для многих операций (например, произвольный доступ); вам не нужно заключать в кавычки вектор, как вы делаете список; и векторы сигнализируют о том, что вы имеете дело с данными, а не с кодом.
Списки подходят, если ваши данные должны расти спереди, а не сзади, или если вы генерируете исходный код в качестве данных (например, в макросах).
[["tiger" "fur" "yellow & black stripes"]
["tiger" "weight" "150"]
["tiger" "home" "India"]
...]
Для получения окончательных данных рассмотрите возможность использования карты строк в картах вместо карты строк в списках. С помощью assoc-in
легко создавать карты карт, потому что он создает промежуточные карты для вас. Затем вы можете получить доступ к подключам ваших данных, используя get-in
.
Чтобы получить доступ к атрибутам животных на вашей карте строк в списках, вам придется выполнить линейный поиск по списку атрибутов. Это будет неудобно для кода и плохо работать.
user> (def animal-map (reduce (fn [m [animal k v]]
(assoc-in m [animal k] v))
{} animals))
#'user/animal-map
user> animal-map
{"frog" {"diet" "insects", "skin" "green"},
"elephant" {"home" "Africa", "weight" "1500", "skin" "gray"},
"tiger" {"home" "India", "weight" "150", "fur" "yellow & black stripes"}}
user> (get-in animal-map ["frog" "diet"])
"insects"
Наконец, я не уверен, откуда поступают эти данные, но рассмотрите возможность использования ключевых слов вместо строк для некоторых из этих ключей. Это может или не может быть подходящим для названий животных, но это почти наверняка подходит для атрибутов животных (вес, дом, рацион).
Если ваши ключи являются ключевыми словами, вам даже не нужно get-in
, вы можете использовать ключевые слова как функции напрямую или использовать ->
. Вы не можете сделать это со строками.
user> (def animal-keyword-map (reduce (fn [m [animal k v]]
(assoc-in m [(keyword animal) (keyword k)] v))
{} animals))
#'user/animal-keyword-map
user> animal-keyword-map
{:frog {:diet "insects", :skin "green"},
:elephant {:home "Africa", :weight "1500", :skin "gray"},
:tiger {:home "India", :weight "150", :fur "yellow & black stripes"}}
user> (:weight (:tiger animal-keyword-map))
"150"
user> (-> animal-keyword-map :tiger :weight)
"150"