带有所选项目的 Clojure 集合原子
Clojure collection atom with selected item
在 Clojure(实际上是 ClojureScript)中完成以下任务的最佳方法是什么:
- 一个可变的元素集合
xs
,每个元素的类型都是 T
(T
是一个映射,如果我们想要具体的话)
- 其中一个“selected元素”,
x
,它在各种xs
或“none selected”状态之间交替。 selected 项的数量是 1 或零。
xs
和 x
将有事件监听器监听它们:一些监听 xs
中的任何变化;有些人听 x
的任何变化。 (也就是说,它们会监听 selected 项目状态的更新,以及 selected 项目的切换。)(我实际上正在使用 Reagent wrapper React,所以这会影响组件更新的时间。)
- 编辑
x
的方法(不需要编辑非selected xs
,但需要能够添加新的xs
)
- 给定
xs
中的一个元素,select 它的方法。 (包括 select "none") 的情况
到目前为止我想到的可能性:
- 使
xs
成为一个由 T
组成的向量的原子,并确保每个 T
元素都知道自己的索引。将 x
替换为 x_idx
,后者存储 selected 项(或 nil
)的索引。选择一个元素只是意味着获取它的索引并将 x_idx
更改为该索引,这两者都是恒定时间操作。这样做的缺点是它使结构有点不那么优雅和简单:我总是传递 selected 项目的 index,以及我想要的每个操作do 必须使用索引而不是项目本身,就像它希望的那样。由于我的 T
对象很小,所以如果有一个 T
. 类型的“selected 对象”变量会更令人愉快
- 使
xs
成为原子向量,x
成为存储T
的原子。现在 x
是 T
,这很好,但是当我想更新关于 x
的信息时,我必须两次调用 reset!
或 swap!
: 一个用于 x
,一个用于 xs
中 x
代表的元素。不雅的原因显而易见。而且我必须快速连续地执行这些操作,否则数据会出现不一致:在两次调用之间,监听 xs
的事件侦听器将看到处于一种状态的 selected 项目,听 x
的人会看到另一种状态。
- 给
T
元素一个字段来判断它们是否 selected,然后去掉 x
。如果可以一次 selected 多个项目,这将是正确的,但由于只能 selected,所以每次我想要 select 时,它只会让我进行线性搜索编辑项目,很烂。
这个问题的重点不是要解决某个特定问题(上述任何可能性都适用于我正在处理的小项目的范围),而是要了解 Clojure 数据结构。这似乎是一种足够普遍的情况,因此围绕它会有一些结构。欢迎回复“您应该尝试完全回答一个不同的问题...”。
你(我)想研究 cursor
s 和 reaction
s,这是试剂原子的两个更高级的特性。它们可用于在其中包含一个集合和一个自动更新的选定元素。例如,参见 here。
假设您有一个 r/atom
保持对象的矢量,并且您想要一个可以更改并且可以直接编辑的选定对象。实现此目的的一种方法是保留一个原子来存储所选项目的索引,然后
(defn my-get-set
([_k] (@vector-of-items @idx-of-selected-item))
([_k v] (reagent.core/rswap! my-state-vector assoc @idx-of-selected-item v)))
(def selected-item (reagent.core/cursor my-get-set []))
编辑: 将 reagent.core/cursor my-get-set nil
更改为 reagent.core/cursor my-get-set []
。前者导致问题。
在 Clojure(实际上是 ClojureScript)中完成以下任务的最佳方法是什么:
- 一个可变的元素集合
xs
,每个元素的类型都是T
(T
是一个映射,如果我们想要具体的话) - 其中一个“selected元素”,
x
,它在各种xs
或“none selected”状态之间交替。 selected 项的数量是 1 或零。 xs
和x
将有事件监听器监听它们:一些监听xs
中的任何变化;有些人听x
的任何变化。 (也就是说,它们会监听 selected 项目状态的更新,以及 selected 项目的切换。)(我实际上正在使用 Reagent wrapper React,所以这会影响组件更新的时间。)- 编辑
x
的方法(不需要编辑非selectedxs
,但需要能够添加新的xs
) - 给定
xs
中的一个元素,select 它的方法。 (包括 select "none") 的情况
到目前为止我想到的可能性:
- 使
xs
成为一个由T
组成的向量的原子,并确保每个T
元素都知道自己的索引。将x
替换为x_idx
,后者存储 selected 项(或nil
)的索引。选择一个元素只是意味着获取它的索引并将x_idx
更改为该索引,这两者都是恒定时间操作。这样做的缺点是它使结构有点不那么优雅和简单:我总是传递 selected 项目的 index,以及我想要的每个操作do 必须使用索引而不是项目本身,就像它希望的那样。由于我的T
对象很小,所以如果有一个T
. 类型的“selected 对象”变量会更令人愉快
- 使
xs
成为原子向量,x
成为存储T
的原子。现在x
是T
,这很好,但是当我想更新关于x
的信息时,我必须两次调用reset!
或swap!
: 一个用于x
,一个用于xs
中x
代表的元素。不雅的原因显而易见。而且我必须快速连续地执行这些操作,否则数据会出现不一致:在两次调用之间,监听xs
的事件侦听器将看到处于一种状态的 selected 项目,听x
的人会看到另一种状态。 - 给
T
元素一个字段来判断它们是否 selected,然后去掉x
。如果可以一次 selected 多个项目,这将是正确的,但由于只能 selected,所以每次我想要 select 时,它只会让我进行线性搜索编辑项目,很烂。
这个问题的重点不是要解决某个特定问题(上述任何可能性都适用于我正在处理的小项目的范围),而是要了解 Clojure 数据结构。这似乎是一种足够普遍的情况,因此围绕它会有一些结构。欢迎回复“您应该尝试完全回答一个不同的问题...”。
你(我)想研究 cursor
s 和 reaction
s,这是试剂原子的两个更高级的特性。它们可用于在其中包含一个集合和一个自动更新的选定元素。例如,参见 here。
假设您有一个 r/atom
保持对象的矢量,并且您想要一个可以更改并且可以直接编辑的选定对象。实现此目的的一种方法是保留一个原子来存储所选项目的索引,然后
(defn my-get-set
([_k] (@vector-of-items @idx-of-selected-item))
([_k v] (reagent.core/rswap! my-state-vector assoc @idx-of-selected-item v)))
(def selected-item (reagent.core/cursor my-get-set []))
编辑: 将 reagent.core/cursor my-get-set nil
更改为 reagent.core/cursor my-get-set []
。前者导致问题。