Функция group-by
полезна здесь:
clojure.core/group-by
([f coll])
Returns a map of the elements of coll keyed by the result of
f on each element. The value at each key will be a vector of the
corresponding elements, in the order they appeared in coll.
Другими словами, group-by
использует данную функцию f
для создания ключа для каждого элемента в coll
, а значение, связанное с этим ключом, является вектором накопленных элементов для этого ключа.
В вашем примере, если мы знаем, что все входные строки гарантированно содержат не менее 5 символов, мы можем использовать subs
. Но проще построить надежное решение, более общее с использованием take
:
(def strings ["snowy10" "catty20" "manny20" "snowy20" "catty10" "snowy20" "catty30" "manny10" "snowy20" "manny30"])
(group-by (partial take 5) strings)
дает нам:
{(\s \n \o \w \y) ["snowy10" "snowy20" "snowy20" "snowy20"]
(\c \a \t \t \y) ["catty20" "catty10" "catty30"]
(\m \a \n \n \y) ["manny20" "manny10" "manny30"]}
Это не совсем то, что мы хотим - мы просто хотим значения карты. Для этого мы используем vals
:
(-> (group-by (partial take 5) strings)
(vals))
и мы получаем:
(["snowy10" "snowy20" "snowy20" "snowy20"]
["catty20" "catty10" "catty30"]
["manny20" "manny10" "manny30"])
Изменить критерии группировки так же просто, как изменить функцию «ключа», которую мы предоставляем, на group-by
. Например, мы можем сгруппировать по последним двум символам в каждой строке, используя take-last
:
(-> (group-by (partial take-last 2) strings)
(vals))
, что дает:
(["snowy10" "catty10" "manny10"]
["catty20" "manny20" "snowy20" "snowy20" "snowy20"]
["catty30" "manny30"])