将对象从数组 A 移动到数组 B。Ramda.js

Move object from array A to array B. Ramda.js

通过 move 移动数组中的项目非常简单,但不幸的是,它并不像往常一样适合我的情况。

例如,我需要将索引为 0 的对象从组 #31 移动到 #33,并将目标数组中对象的新索引设置为 1。

数据对象模型:

const stuff = {
  "31": [
    {------------------------------|
      "id": "11",                  |============|
      "title": "Just move me pls"  |           ||
    },-----------------------------|           ||
    {                                          ||
      "id": "12",                              ||
      "title": "Ramda 123"                     ||
    },                                         ||
  ],                                           ||
  "33": [                                      ||
    {                                          ||
      "id": "3",                               ||
      "title": "Ramda jedi"                    ||
    }                                          ||
     ◀==========================================|
  ],   
  "4321": [
    {
      "id": "1",
      "title": "Hello Ramda"
    }
  ]
}

有谁知道如何解决这个问题?

简而言之Javascript,Array#splice效果很好。

const stuff = { 31: [{ id: "11", title: "just move me pls" }, { id: "12", title: "ramda 123" }], 33: [{ id: "3", title: "..." }], 4321: [{ id: "1", title: "hello Ramda" }] };

stuff['33'].splice(1, 0, ...stuff['31'].splice(0, 1));

console.log(stuff);
.as-console-wrapper { max-height: 100% !important; top: 0; }

除非您需要以编程方式执行此操作,否则您可以使用 Javascript 数组方法简单地移动对象。

stuff[33][1] = stuff[31][0]
// index 1 at key 33 gets assigned index 0 at key 31

stuff[31].shift()
// remove the first array element and shift all others to a lower index

您可以使用镜头来更改子对象,但您首先需要获得该项目。

首先使用 R.viewR.lensPath 来获取物品。然后使用 R.overR.lenseProp 从源键和索引(sksi)的子对象中删除项目,然后将其插入到目标键和索引 (tk, ti).

更新:添加目标,如果key(tk)不存在,使用R.unless与[=23=检查] 对于 tk 的存在,如果它不添加空数组 R.assoc.

const { curry, view, lensPath, pipe, over, lensProp, remove, unless, has, assoc, insert } = R;

const fn = curry(({ key: sk, idx: si }, { key: tk, idx: ti }, obj) => {
  const item = view(lensPath([sk, si]), obj); // get the item
  
  return pipe(
    over(lensProp(sk), remove(si, 1)), // remove the item from the source
    unless(has(tk), assoc(tk, [])), // add target if it's missing
    over(lensProp(tk), insert(ti, item)), // move to the target
  )(obj);
});

const stuff = { 31: [{ id: "11", title: "just move me pls" }, { id: "12", title: "ramda 123" }], 33: [{ id: "3", title: "..." }], 4321: [{ id: "1", title: "hello Ramda" }] };

console.log(fn({ key: '31', idx: 0 }, { key: 33, idx: 1 }, stuff));
console.log(fn({ key: '31', idx: 0 }, { key: 555, idx: 1 }, stuff));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

我是 Ramda 的创始人之一,也是 Ramda 的忠实粉丝。但 Ramda 主要是在我们可以依靠 ES6+ 技术之前的日子里构建的,虽然我仍然经常使用它,但现在使用 vanilla JS 某些事情也一样容易。这是我的方法,它仍然使用 insertremove Ramda 辅助函数:

const moveItem = (
  srcKey, srcIdx, destKey, destIdx, obj,
  {[String (srcKey)]: src, [String (destKey)]: dest, ...rest} = obj
) => ({
  [srcKey]: remove (srcIdx, 1, src),
  [destKey]: insert (destIdx, src [srcIdx], dest || []),
  ...rest
})

const stuff = {"31": [{"id": "11", "title": "Just move me pls"}, {"id": "12", "title": "Ramda 123"}], "33": [{"id": "3", "title": "Ramda jedi"}], "4321": [{"id": "1", "title": "Hello Ramda"}]}

console.log (
  moveItem (31, 0, 33, 1, stuff)
)

console.log ( // destination doesn't exist
  moveItem (31, 0, 35, 1, stuff)
)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {remove, insert} = R                                  </script>

注意dest || []是为了处理目标对象不存在的情况

我绝不会仅仅为了获得这些辅助函数而引入 Ramda,因为只需要一点额外的代码就可以很容易地编写没有它们的等价物:

const moveItem = (
  srcKey, srcIdx, destKey, destIdx, obj,
  {[String (srcKey)]: src, [String (destKey)]: dest, ...rest} = obj
) => ({
  [srcKey]: [... src .slice (0, srcIdx), ... src .slice (srcIdx + 1)],
  [destKey]: [...(dest || []) .slice (0, destIdx), src [srcIdx], ...(dest || []) .slice (destIdx)],
  ...rest
})

但是,由于我通常将 Ramda 包含在我的项目中,我仍然倾向于立即想到它的功能。

我认为这不一定比 Ori Drori 基于镜头的解决方案更好。当您必须专注于结构的一部分时,伸手去拿镜头可能是一个好习惯。但这也不一定更糟。尽可能简单地编写代码有一些强大的好处,我确实发现这有点简单。


还有一件事。关于对 Nina 回答的评论:

I know about native solution, but I want to solve this with more functional way:) (with Ramda)

我不喜欢 Nina 的解决方案,因为它存在固有的突变,这是拒绝它的完全合理的理由。但是,如果这是学习 Ramda 的练习,那么 "with Ramda" 应该只是目标。如果您的主要工作单元是函数并且您的函数是纯函数并且您不改变用户数据,那么您就是在进行函数式编程,而不管您可能使用的是什么库。