我有两个数组对象如下:
var arr1 = [
{
name: 1,
value: 10
},
{
name: 2,
value: 15
}
]
var arr2 = [
{
name: 3,
value: 5
},
{
name: 4,
value: 3
}
]
我想重新定义密钥并使用相同的索引减少每个数据。
输出:
var arr1 = [
{
itemLabel: 1,
itemValue: 5
},
{
itemLabel: 2,
itemValue: 12
}
]
我现在正在做以下事情:
formatData = arr1.map((row, index) => ({
itemLabel: arr1.name,
itemValue: arr1.value - arr2[index].value
}))
有没有更好的解决方案呢?
答案 0 :(得分:1)
你的代码很好,你也可以使用递归:
var arr1 =[{
name: 1,
value: 10
}, {
name: 2,
value: 15
}];
var arr2= [{
name: 3,
value: 5
}, {
name: 4,
value: 3
}]
const createObject=(arr1,arr2,ret=[])=>{
if(arr1.length!==arr2.length){
throw("Arrays should be the same length.")
}
const item = {
itemLabel: arr1[0].name,
itemValue: arr1[0].value - arr2[0].value
};
if(arr1.length===0){
return ret;
};
return createObject(arr1.slice(1),arr2.slice(1),ret.concat(item));
}
console.log(createObject(arr1,arr2));
实现map
或reduce
的两个函数都必须在其作用域之外使用arr1或arr2(不作为参数传递给它),因此严格来说不是纯粹的。但你可以通过部分应用轻松解决它:
var arr1 =[{
name: 1,
value: 10
}, {
name: 2,
value: 15
}];
var arr2= [{
name: 3,
value: 5
}, {
name: 4,
value: 3
}];
const mapFunction = arr2 => (item,index) => {
return {
itemLabel: item.name,
itemValue: item.value - arr2[index].value
}
}
var createObject=(arr1,arr2,ret=[])=>{
if(arr1.length!==arr2.length){
throw("Arrays should be the same length.")
}
const mf = mapFunction(arr2);
return arr1.map(mf);
}
console.log(createObject(arr1,arr2));
但正如评论中提到的CodingIntrigue:这些都没有比你已经做过的“更好”。
答案 1 :(得分:1)
一人军
一个简单的递归程序,可以处理单个函数中的所有内容。这里有一个明显的问题混合,这会损害功能的整体可读性。我们将在下面看到针对此问题的一种补救措施
const main = ([x, ...xs], [y, ...ys]) =>
x === undefined || y === undefined
? []
: [ { itemLabel: x.name, itemValue: x.value - y.value } ] .concat (main (xs, ys))
const arr1 =
[ { name: 1, value: 10 }, { name: 2, value: 15 } ]
const arr2 =
[ { name: 3, value: 5 }, { name: 4, value: 3 } ]
console.log (main (arr1, arr2))
// [ { itemLabel: 1, itemValue: 5 },
// { itemLabel: 2, itemValue: 12 } ]

用类型思考
答案的这一部分受到Monoid类别的类型理论的影响 - 我不太擅长,因为我认为代码应该能够证明自己。
所以我们在问题中有两种类型:我们称它们为Foo和Bar
Foo
- 有name
和value
字段Bar
- 有itemLabel
和itemValue
字段我们可以代表我们的"类型"但是我们想要,但我选择了一个构造对象的简单函数
const Foo = (name, value) =>
({ name
, value
})
const Bar = (itemLabel, itemValue) =>
({ itemLabel
, itemValue
})
制作类型的值
要构造我们类型的新值,我们只需将函数应用于字段值
const arr1 =
[ Foo (1, 10), Foo (2, 15) ]
const arr2 =
[ Foo (3, 5), Foo (4, 3) ]
让我们看看到目前为止的数据
console.log (arr1)
// [ { name: 1, value: 10 },
// { name: 2, value: 15 } ]
console.log (arr2)
// [ { name: 3, value: 5 },
// { name: 4, value: 3 } ]
一些高级别计划
我们有一个良好的开端。我们有两个Foo值数组。我们的目标是通过从每个数组中取一个Foo值,将它们组合起来(稍后将详细介绍),然后转移到下一对数据来完成两个数组
const zip = ([ x, ...xs ], [ y, ...ys ]) =>
x === undefined || y === undefined
? []
: [ [ x, y ] ] .concat (zip (xs, ys))
console.log (zip (arr1, arr2))
// [ [ { name: 1, value: 10 },
// { name: 3, value: 5 } ],
// [ { name: 2, value: 15 },
// { name: 4, value: 3 } ] ]
合并值:concat
将Foo值正确地组合在一起,我们现在可以更多地关注组合过程。在这里,我将定义一个通用的concat
,然后在我们的Foo类型上实现它
// generic concat
const concat = (m1, m2) =>
m1.concat (m2)
const Foo = (name, value) =>
({ name
, value
, concat: ({name:_, value:value2}) =>
// keep the name from the first, subtract value2 from value
Foo (name, value - value2)
})
console.log (concat (Foo (1, 10), Foo (3, 5)))
// { name: 1, value: 5, concat: [Function] }
concat
听起来很熟悉吗? Array和String也是Monoid类型!
concat ([ 1, 2 ], [ 3, 4 ])
// [ 1, 2, 3, 4 ]
concat ('foo', 'bar')
// 'foobar'
高阶函数
所以现在我们有办法将两个Foo值组合在一起。保留第一个Foo的name
,并减去value
属性。现在我们将这个应用于我们的"压缩"结果。功能程序员喜欢高阶函数,所以你会欣赏这种高阶和谐
const apply = f => xs =>
f (...xs)
zip (arr1, arr2) .map (apply (concat))
// [ { name: 1, value: 5, concat: [Function] },
// { name: 2, value: 12, concat: [Function] } ]
转换类型
现在我们的Foo值具有正确的name
和value
值,但我们希望我们的最终答案为Bar值。我们需要一个专门的构造函数
Bar.fromFoo = ({ name, value }) =>
Bar (name, value)
Bar.fromFoo (Foo (1,2))
// { itemLabel: 1, itemValue: 2 }
zip (arr1, arr2)
.map (apply (concat))
.map (Bar.fromFoo)
// [ { itemLabel: 1, itemValue: 5 },
// { itemLabel: 2, itemValue: 12 } ]
努力工作得到回报
美丽,纯粹的功能表达。我们的课程读得非常好;由于声明式的风格,数据的流动和转换很容易遵循。
// main :: ([Foo], [Foo]) -> [Bar]
const main = (xs, ys) =>
zip (xs, ys)
.map (apply (concat))
.map (Bar.fromFoo)
完整的代码演示,当然
const Foo = (name, value) =>
({ name
, value
, concat: ({name:_, value:value2}) =>
Foo (name, value - value2)
})
const Bar = (itemLabel, itemValue) =>
({ itemLabel
, itemValue
})
Bar.fromFoo = ({ name, value }) =>
Bar (name, value)
const concat = (m1, m2) =>
m1.concat (m2)
const apply = f => xs =>
f (...xs)
const zip = ([ x, ...xs ], [ y, ...ys ]) =>
x === undefined || y === undefined
? []
: [ [ x, y ] ] .concat (zip (xs, ys))
const main = (xs, ys) =>
zip (xs, ys)
.map (apply (concat))
.map (Bar.fromFoo)
const arr1 =
[ Foo (1, 10), Foo (2, 15) ]
const arr2 =
[ Foo (3, 5), Foo (4, 3) ]
console.log (main (arr1, arr2))
// [ { itemLabel: 1, itemValue: 5 },
// { itemLabel: 2, itemValue: 12 } ]

<强>说明强>
我们上面的程序是使用.map
- .map
链实现的,这意味着多次处理和创建中间值。我们在调用[[x1,y1], [x2,y2], ...]
时创建了一个zip
的中间数组。类别理论为我们提供了诸如等式推理之类的东西,因此我们可以用m.map(f).map(g)
替换m.map(compose(f,g))
并获得相同的结果。所以还有改进空间的空间,但我认为这足以削减你的牙齿并开始以不同的方式思考问题。
答案 2 :(得分:0)
为了使您的解决方案更具功能性,您需要将匿名函数更改为纯(匿名)函数。
纯函数是一个函数,在给定相同输入的情况下,它将始终返回相同的输出
匿名函数取决于可变变量arr1
和arr2
。这意味着它取决于系统状态。所以它不适合纯函数规则。
以下可能不是最好的实现,但我希望它能给你一个想法......
为了使其纯粹,我们可以将变量作为参数传递给函数
const mapWithObject = (obj2, obj1, index) => ({
itemLabel: obj1.name,
itemValue: obj1.value - obj2[index].value
})
// example call
const result = mapWithObject(arr2, arr1[0], 0)
好的,但现在该函数不再适合map
,因为它需要3个参数而不是2 ..
const mapWithObject = obj2 => (obj1, index) => ({
itemLabel: obj1.name,
itemValue: obj1.value - obj2[index].value
})
const mapObject_with_arr2 = mapWithObject(arr2)
// example call
const result = mapObject_with_arr2(arr1[0], 0)
const arr1 = [{
name: 1,
value: 10
},
{
name: 2,
value: 15
}
]
const arr2 = [{
name: 3,
value: 5
},
{
name: 4,
value: 3
}
]
const mapWithObject = obj2 => (obj1, index) => ({
itemLabel: obj1.name,
itemValue: obj1.value - obj2[index].value
})
const mapObject_with_arr2 = mapWithObject(arr2)
const mappedObject = arr1.map(mapObject_with_arr2)
console.log(mappedObject)
答案 3 :(得分:0)
如果您不太关心性能,但想要进一步区分您的疑虑,可以使用这种方法:
定义一个执行&#34;配对的功能&#34;在arr1
和arr2
[a, b, c] + [1, 2, 3] -> [ [ a, 1 ], [ b, 2 ], [ c, 3 ] ]
定义一个能清楚显示两个对象的合并策略的函数
{ a: 1, b: 10 } + { a: 2, b: 20 } -> { a: 1, b: -10 }
以下是一个例子:
var arr1=[{name:1,value:10},{name:2,value:15}],arr2=[{name:3,value:5},{name:4,value:3}];
// This is a very general method that bundles two
// arrays in an array of pairs. Put it in your utils
// and you can use it everywhere
const pairs = (arr1, arr2) => Array.from(
{ length: Math.max(arr1.length, arr2.length) },
(_, i) => [ arr1[i], arr2[i] ]
);
// This defines our merge strategy for two objects.
// Ideally, you should give it a better name, based
// on what the objects represent
const merge =
(base, ext) => ({
itemLabel: base.name,
itemValue: base.value - ext.value
});
// This is a helper that "applies" our merge method
// to an array of two items.
const mergePair = ([ base, ext ]) => merge(base, ext);
// Another helper that composes `pairs` and `mergePair`
// to allow you to pass your original data.
const mergeArrays = (arr1, arr2) => pairs(arr1, arr2).map(mergePair);
console.log(mergeArrays(arr1, arr2));
&#13;