想转换(使用Ramda)
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
进入
var b = {1:'one', 2:'two', 3:'three'}
我对函数式编程非常陌生,并且愿意接受任何想法。
我认为我们必须做的是,使用以{}开头的reduce函数,然后在每次迭代中将当前元素的ID和名称添加到哈希表中。这是我想出的,似乎很错误。我要关闭吗?
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'},{id: 4, name: 'four'} ]
var b = R.reduce(R.assoc(R.prop('id'), R.prop('name')), {}, a)
b
答案 0 :(得分:2)
有很多方法都可以使用。所有其他正确答案有助于证明这一点。我将在下面列出一些我自己的。但首先,
您尝试这样做:
R.reduce(R.assoc(R.prop('id'), R.prop('name')), {}, a)
很明显,您要在这里做什么。问题在于R.prop('id')
和R.prop('name')
是函数。 R.assoc
不接受功能;它需要一个字符串(实际上将使用数字)和一个任意值。因此assoc
不能以这种方式与它们一起使用。
清除此错误的一种尝试是认识到可以将函数视为值的“容器” 。以某种(也许令人惊讶,但非常有用)的方式,函数是其返回值的容器。 R.lift
旨在将对值起作用的函数转换为对值的容器起作用的函数。它的工作方式如下:R.multiply
接受数字。如果我们 lift multiply
,则结果函数将接受数字容器。像这样:
R.lift(R.multiply)(Maybe.Just(5), Maybe.Just(3)) // Maybe.Just(15)
如果我们为lift(multiply)
提供两个函数,那么我们将返回一个函数,该函数返回将它们的返回值相乘的结果:
const area = R.lift(R.multiply)(prop('width'), prop('height'))
area({width: 5, height: 3})
所以也许我们可以用lift
更新您的技术:
R.reduce(R.lift(R.assoc)(R.prop('id'), R.prop('name'), identity), {}, a)
不幸的是,这再次失败。这次的麻烦是reduce
进行了二进制回调,同时提供了累加器和当前值。但是R.prop('id')
和R.prop('name')
无法识别。他们在累加器上寻找相关属性,而这些属性根本就不存在。
我们也许仍然可以解决此问题,但是在这一点上,我们将失去这种解决方案的简单性。因此,让我们看看其他可能性。
这两个版本中的每个版本都使用一个简单的reduce
调用,这是您的解决方案试图做到的:
const convertToHash = reduce((acc, {id, name}) => merge(acc, {[id]: name}), {})
和
const convertToHash = reduce((acc, {id, name}) => ({...acc, [id]: name}), {})
它们几乎相同。两者都会在每次迭代中创建一次性对象。在第一个中,您可以将R.merge
替换为Object.assign
而没有任何实际问题,因为所产生的突变是该函数的内部。第二个似乎更优雅,但它会在每次迭代时重建整个累加器。随着针对ES6的引擎优化的进行,这最终可能不会成为性能问题,但现在可能会出现,尤其是在性能关键代码中。
zipWith
Ramda的zip
函数采用两个列表,并将它们逐个位置地组合为一个列表。 R.zipWith
接受用于将两个元素合并为一个的函数。在这里,我们使用R.objOf
,它将名称和值转换为单属性对象。 (objOf('foo', 42) //=> {foo: 42}
。)
const convertToHash = compmose(mergeAll, lift(zipWith(objOf))(pluck('id'), pluck('name')))
如上所述,我们使用lift
来使zipWith(objOf)
与函数一起工作。这样会产生类似[{"1": "one"}, {"2": "two"}, {"3": "three"}]
的内容,然后将其传递给R.mergeAll
以创建单个对象。
props
和fromPairs
此解决方案使用R.props
和R.fromPairs
。 fromPairs
接受名称/值对的列表(作为两个元素的数组),并将它们转换为单个对象。 props
将命名的属性拉入一个独立的数组。 Mapping
超过原始列表,这给了我们fromPairs
的输入:
const convertToHash = compose(fromPairs, map(props(['id', 'name'])))
尽管我很喜欢zipWith
解决方案,并且如果它的输出是我想要的,它将使用它,而必须添加mergeAll
使得一眼就很难理解。因此,这种解决方案赢得了我的最佳Ramda选择。
答案 1 :(得分:1)
您可以通过以下方法实现此目标:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
var b = R.reduce((dict, item) => ({ ...dict, [ item.id ] : item.name }), {}, a)
此方法使用es6语法在每次精简迭代期间将带有值(item.id
的键(通过item.name
命名)添加到结果字典中。
答案 2 :(得分:1)
您可以创建管道(R.pipe)来将对象数组转换为哈希:
const a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
const convertToHash = (props) =>
R.pipe(
R.map(R.props(props)),
R.fromPairs
);
const result = convertToHash(['id', 'name'])(a);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
答案 3 :(得分:0)
尝试使用此代码:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
R.map(i=> {
var n = []
n[R.keys(i)[0]] = i.name
return n
},a)
答案 4 :(得分:0)
使用es6时,您可以获得更灵活的解决方案
let a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
let out = a.reduce((acc, {id, name}) => {
acc[id] = name;
return acc;
}, {});
console.log(out)
答案 5 :(得分:0)
您可以循环初始数组并分配给新对象:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
var new_a = {};
a.forEach(function(e) {
new_a[e.id] = e.name;
});
console.log(new_a);