一般来说:如何获取两个数组并应用一个函数来同时迭代这两个数组并更新它们的值?
具体:
我有一个按钮列表和一个位置列表,通过如下方式创建:
let buttons:Array<Button> = makeButtons();
let positions:Array<number> = R.scan(
(total, width) => total + width,
0,
R.map(button => button.width, buttons));
我现在如何获取位置列表并将其应用到按钮?
与此相关的是我另外感到困惑的事情 - 是否有一种技术可以控制修改是否发生在按钮本身上,还是返回与输入具有相同“形状”的新按钮?
我想在某些情况下我想要执行其中任何一个(例如,如果修改屏幕上的现有按钮而不需要重新绘制它们,而不是保持更纯粹)
最佳答案
您正在寻找的是 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);
关于javascript - 如何应用两个数组的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44571684/