You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Specter实现按idx位置在有序列表中插入实体?

用Specter改写按idx有序插入元素的函数

问题背景

现有已按:idx字段有序排列的Clojure列表:

[{:identifier "Green", :idx 2} {:identifier "Indigo", :idx 4} {:identifier "Violet", :idx 5}]

需要插入如下实体:

{:identifier "Blue", :idx 3}

最终期望得到的结果为:

[{:identifier "Green", :idx 2} {:identifier "Blue", :idx 3} {:identifier "Indigo", :idx 4} {:identifier "Violet", :idx 5}]

失败的尝试

我尝试用以下Specter代码实现,但未达到预期效果:

(s/setval [s/ALL (s/pred #(> (:idx %) idx)) s/FIRST s/BEFORE-ELEM] {:identifier "Blue", :idx 3} xs)

需求目标

  1. 定位列表中第一个:idx值大于传入idx参数的元素
  2. 在该元素的前面插入新实体

原Clojure实现

已用原生Clojure写出功能正常的函数:

(defn insert-inbetween-by-idx [xs identifier idx]
  (let [insert {:identifier identifier :idx idx}
        b4-idx (filterv (comp (partial > idx) :idx) xs)
        after-idx (filter (comp (partial < idx) :idx) xs)]
    (reduce into [b4-idx [insert] after-idx])))

Specter改写方案

利用Specter的导航器可以更简洁地实现该功能,改写后的函数如下:

(require '[com.rpl.specter :as s])

(defn insert-inbetween-by-idx [xs identifier idx]
  (let [insert {:identifier identifier :idx idx}]
    (s/setval [(s/first (s/pred #(> (:idx %) idx))) s/BEFORE-ELEM] insert xs)))

关键说明

  • (s/first (s/pred #(> (:idx %) idx))):精准定位列表中第一个:idx大于目标idx的元素
  • s/BEFORE-ELEM:导航到该元素的前置位置,完成插入操作
  • 边界情况处理:如果列表中所有元素的:idx都小于等于目标idx,新元素会自动插入到列表末尾

内容的提问来源于stack exchange,提问作者Chris Murphy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:32:39