如何应用两个数组的值?

how to apply values of two arrays?

一般来说:我如何获取两个数组并应用一个函数同时迭代它们并更新它们的值?

具体来说:

我有一个按钮列表和一个位置列表,它们是通过这样的方式创建的:

let buttons:Array<Button> = makeButtons();
let positions:Array<number> = R.scan(
  (total, width) => total + width, 
  0, 
  R.map(button => button.width, buttons));

我现在如何获取位置列表并将它们应用到按钮?

与此相关的是我另外感到困惑的事情 - 是否有一种技术可以控制修改是发生在按钮本身上还是返回一个与输入相同 "shape" 的新按钮?

我想在某些情况下我想做其中任何一个(例如,如果修改屏幕上现有的按钮而不需要重新绘制它们,而不是保持更纯净)

你要找的是zipWith:

zipWith((but, pos) => assoc('position', pos, but), buttons, positions)

请注意,此处使用的 scan 将给出比原始列表中包含的元素多一个元素:第一个元素是累加器的初始值。但是 zipWith 当最小列表用完时停止。根据您是要包含第一个值还是最后一个值,您可能必须添加对 tail 的调用。 (我想这里的位置应该是按钮的左侧,这不是必需的。)

另请注意,您正在重写 Ramda 附带的一些函数:

let positions = R.scan(
  (total, width) => total + width, 
  0, 
  R.map(button => button.width, buttons));

你可以得到与

相同的结果
let positions = R.scan(R.add, 0, R.pluck('width', buttons))

现在,如果您愿意,您也可以通过使用稍微复杂一点的累加器来完成此操作:

R.compose(R.prop('buttons'), R.reduce((all, curr) => {
  const buttons = append(assoc('position', all.pos, curr), all.buttons);
  const pos = all.pos + curr.width;
  return {pos, buttons}
}, {pos: 0, buttons: []}))(buttons)

这将通过一次数据构建您的结构。我实际上不会在这里推荐这个。当我真的想避免中间结构或通过列表进行多次迭代时,这是我使用的一种技术,但它是一个有趣的替代方法。

您可以在 Ramda REPL.

中看到所有这些

对此:

Related to this is something I'm additionally confused about - is there a technique to control whether the modification is happening on the button itself vs. returning a new button with the same "shape" as the input?

Ramda 的理念是永不 修改您的输入。所以如果你使用像 R.assoc 这样的东西,你总是会得到新的东西。并且 Ramda 不会尝试复制它的继承层次结构。如果你想原地修改按钮,我的第一个建议是重新考虑,因为 Ramda 的理由是合理的,但如果你仍然想,那么只需将上面的第一个建议更改为

zipWith((but, pos) => {but.position = pos; return but}, buttons, positions);