一种常见的模式是将问题拆分为多个部分,为每个部分创建一个表达式,然后将它们连接在一起(->> 发音为“thread last”,它将每个表达式的输出传递给最后一个参数位置)在这种情况下,我看到三个阶段:
- 按年龄对它们进行排序,以获得彼此相邻的相似年龄
- 按年龄将序列分成块
- 将每个组格式化为 [age-in-group whole-group
可以写成:
user> (def my-data [{:gender "male" :name "Gabriel" :age 25}
{:gender "female" :name "Jane" :age 25}
{:gender "female" :name "Alice" :age 22}])
#'user/my-data
user> (->> my-data
(sort-by :age)
(partition-by :age)
(map (fn [group] [(keyword (str (:age (first group)))) group]))
reverse)
([:25 ({:gender "male", :name "Gabriel", :age 25}
{:gender "female", :name "Jane", :age 25})]
[:22 ({:gender "female", :name "Alice", :age 22})])
最后的反转只是将其按降序排列,以匹配您所需的输出样式。重要的想法是制作几个小的表达式,每个表达式都解决问题的一部分,然后组合它们来解决整体问题。
您可能还想了解地图上的group-by 函数,它采用一系列地图,几乎可以直接解决您的问题。
user> (group-by :age my-data)
{25 [{:gender "male", :name "Gabriel", :age 25}
{:gender "female", :name "Jane", :age 25}],
22 [{:gender "female", :name "Alice", :age 22}]}
它返回一个映射而不是序列(或向量),并且不会将键转换为关键字。出于实际原因,它可能是大多数此类问题的答案。同样重要的部分是组合较小的解决方案以方便解决较大的问题。