Functional programming 映射时如何合并两个数组?
背景:我对Ramda和FP相当陌生。我发现自己遇到了这样的情况:我有两个输入Functional programming 映射时如何合并两个数组?,functional-programming,ramda.js,Functional Programming,Ramda.js,背景:我对Ramda和FP相当陌生。我发现自己遇到了这样的情况:我有两个输入itemList和costList。列表中的值具有基于idx的关系。因此itemList[0]和costList[0]表示可以在同一对象中的值(例如{item:itemList[0],cost:costList[0]})。因此,另一种解决方案可以从合并itemList和costList开始。我对其中一种或两种解决方案都感兴趣。任何其他提示和建议也将不胜感激 let itemList = ['shirt', 'shoe
itemList
和costList
。列表中的值具有基于idx的关系。因此itemList[0]
和costList[0]
表示可以在同一对象中的值(例如{item:itemList[0],cost:costList[0]}
)。因此,另一种解决方案可以从合并itemList和costList开始。我对其中一种或两种解决方案都感兴趣。任何其他提示和建议也将不胜感激
let itemList = ['shirt', 'shoes'];
let costList = ['shirtCost', 'shoesCost'];
let formulaList = R.map(
x => ({
formulaXAttr: x,
formulaYAttr: 'tbd later',
})
)(itemList);
let finalList = R.map(
x => R.merge(x, {formulaYAttr: '???'}) // how to merge in costList?
)(formulaList);
// this is how i'd do it in vanilla JS
let finalList = formulaList.map((x, idx) => ({
...x,
formulaYAttr: costList[idx],
}));
您在Ramda中寻找的函数被调用,它接受一个需要两个参数的函数,第一个列表中的每个元素一个参数,第二个列表中的成对元素一个参数。这将作为一个列表结束,该列表与提供的两个列表中的较短列表一样长,包含为每对调用函数的结果
const itemList=['shirt','shoes'];
const costList=['shirtCost','shoesCost'];
常数fn=R.zipWith((x,y)=>
({formulaXAttr:x,formulaYAttr:y}))
console.log(
fn(项目清单、成本清单)
)
斯科特·克里斯托弗的答案显然是正确的
zipWith
正是为这种情况而设计的。在标题中,您将询问如何在映射时执行此操作。我想指出的是,尽管拉姆达确实为此提供了一个选项(详情请参见),但人们普遍不赞成它。这样做的原因对于更多地了解FP很重要
对map
的一种理解是,它通过对每个元素应用给定函数,将一种类型的元素列表转换为另一种类型的元素列表。这是一个很好的公式,但有一个更一般的公式:map
通过对每个元素应用给定函数,将一种类型的元素容器转换为另一种类型的元素容器。换句话说,映射的概念可以应用于许多不同的容器,而不仅仅是列表。该规范为具有map
方法的容器定义了一些规则。具体类型为,但对于那些没有相关数学背景的人,这可以被认为是可映射的
。Ramda应能与以下类型进行良好的互操作:
const square = n => n * n;
map(square, [1, 2, 3, 4, 5]) //=> [1, 4, 9, 16, 25]
// But also, if MyContainer is a Functor
map(square, MyContainer(7)) //=> MyContainer(49)
// and, for example, if for some Maybe Functor with Just and Nothing subtypes
const {Just, Nothing} = {Maybe}
// then
map(square, Just(6)) //=> Just(36)
map(square, Nothing()) //=> Nothing()
Ramda的map
函数只使用容器的元素调用提供的转换函数。它不提供索引。这是有意义的,因为并非所有容器都有索引的概念
正因为如此,映射是不正确的,Ramda不是尝试匹配索引的地方。但这是拉姆达的核心。如果您想合并两个元素通过索引匹配的列表,您可以像Scott使用zipWith
做的那样简单。但您也可以使用zip
,其工作原理如下:
zip(['a', 'b', 'c', 'd'], [2, 3, 5, 7]) //=> [['a', 2], ['b', 3], ['c', 5], ['d', 7]]
然后对结果对调用map
zipWith
只需一步即可完成同样的操作。但是如果没有它,像map
和zip
这样的原语仍然可以组合起来做你想做的事情。除了这里的其他答案,我想向你展示如何自己编写这种东西。Ramda库并不总是为您提供一行解决方案,如果您将解决方案限制为仅使用Ramda提供的函数,那么您将有所保留
这种做法将使您有信心尝试编写自己的程序。当/如果您发现Ramda具有一些您需要的功能时,您可以轻松地重构程序以使用Ramda提供的功能
const无=
符号()
常数zipWith=(f[x=None,…xs],[y=None,…ys])=>
x==无| | y==无
? []
:[f(x,y)].concat(zipWith(f,x,y))
console.log
(齐普威思)
((名称,价格)=>({name,price})
,[“鞋子”,“裤子”]
, [ 19.99, 29.99 ]
)
)
//[{名称:“鞋”,价格:19.99}
//,{名称:“裤子”,价格:29.99}
//]
如果要使用一个附加参数,为什么不使用默认为[]
的累加器,只需使用列表的长度在基本大小写和递归大小写之间切换?有了这一点,您可以在可用的情况下利用尾部调用优化。None
符号是一种有趣的方法,但我发现它更难一目了然。感谢您的详细解释。我在转换和聚合JSON负载时遇到了这个问题zipWith
帮助我解决最初的问题。但是,我对使用zipWith
的解决方案并不完全满意。希望我能找到解决类似问题的另一种方法。你会说如果我过于依赖zip
函数,那么这是否意味着有什么(不好的)东西?如果是这样,我处理这个问题的方式与使用zip
有什么不同?@epikhighs:我想说zip
对于处理来自其他来源的数据非常有用。但是,如果你在自己的数据结构内部大量使用它,那么最好考虑其他的结构。使用共享索引既尴尬又有点太复杂。