Array.reduce 多维数组到对象数组
Array.reduce on a multidimensional array to array of objects
在我的扑克应用程序中,我有一组手牌,每手牌都是随机选择的具有价值和花色的纸牌对象的数组:
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
为了准备评估手,我想使用 Array.reduce 到 return 手对象数组。所以输出将是:
[
{
values: [5, 4, 6, 11, 12],
suits: ['s', 's', 'c', 'd', 'c']
},
{
values: [9, 12, 8, 12, 2],
suits: ['d', 'h', 'c', 's', 's']
},
{
values: [4, 6, 10, 3, 7],
suits: ['h', 's', 'c', 'd', 'd']
}
]
我尝试用嵌套的 forEach 实现它,但它失败了,我不知道为什么。我有两个 console.log,其中的输出符合预期,但最终 hands 与输入相同。
let temp = []
hands.forEach((el) => {
temp = el
el = {}
el.values = []
el.suits = []
console.log(el) //expected output
temp.forEach((obj) => {
el.values.push(obj.value)
el.suits.push(obj.suit)
console.log(el) //expected output
})
})
console.log(hands) //same as original
好了 - 使用嵌套 Array.prototype.reduce
函数的解决方案:
var array=[[{value:5,suit:'s'},{value:4,suit:'s'},{value:6,suit:'c'},{value:11,suit:'d'},{value:12,suit:'c'}],[{value:9,suit:'d'},{value:12,suit:'h'},{value:8,suit:'c'},{value:12,suit:'s'},{value:2,suit:'s'}],[{value:4,suit:'h'},{value:6,suit:'s'},{value:10,suit:'c'},{value:3,suit:'d'},{value:7,suit:'d'}]];
var result = array.reduce(function(p, c) {
p.push(c.reduce(function(a, b) {
a.values.push(b.value);
a.suits.push(b.suit);
return a;
}, {values: [],suits: []}));
return p;
},[]);
console.log(result);
.as-console-wrapper {top: 0;max-height: 100%!important;}
这是一个使用 string concat
和 reduce
的简单解决方案。你可以尝试这样的事情:
var reduced = [];
//here a is your initial array
for(var i=0; i<a.length;i++){
reduced.push(a[i].reduce(function(prev,curr){
var obj={value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj}));
}
console.log(reduced)
编辑:根据@Barmar 评论这个returns 字符串。如果你想要一个数组,你可以这样做:
for(var i=0; i<a.length;i++){
var tempElm =a[i].reduce(function(prev,curr) {
var obj= {value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj});
tempElm['value'] = tempElm['value'].split();
tempElm['suit']= tempElm['suit'].split();
reduced.push(tempElm);
}
console.log(reduced)
编辑 2: 由于对上述修复的公平批评(增加了将字符串转换为数组的开销),您可以直接创建数组,如下所示:
var reduced = [];
for(var i=0; i<a.length;i++){
var valArray = []; var suitArray=[];
var tempElm = a[i].reduce(function(prev,curr) {
valArray.push(curr.value);suitArray.push(curr.suit);
var obj= {value:valArray,suit:suitArray};
return obj;
},null);
console.log(reduced)
您必须考虑输入数据 (DATA
) 和输出 (DATA'
)
的形状
注意 1:1 HAND
和 HAND'
之间的关系意味着我们将使用 Array.prototype.map
进行一次转换。另一方面,CARD
与 HAND'
有 N:1 关系,这意味着我们将使用 Array.prototype.reduce
进行转换
所以在我们工作的时候请记住,我们将做一个 map 和一个 reduce
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
let output =
data.map(cards =>
cards.reduce(({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
}), {values: [], suits: []}))
console.log(output)
现在当然看起来有点密集,所以如果我们能稍微降低复杂性就好了。通过为 map
和 reduce
制作一些柯里化适配器,我们可以表达一个可以很好地执行转换的函数
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
const map = f => xs => xs.map(f)
const reduce = f => y => xs => xs.reduce(f, y)
const handAppendCard = ({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
})
const makeHands =
map (reduce (handAppendCard) ({values:[], suits:[]}))
let output = makeHands (data)
console.log(output)
这只是解决问题的一种方法。希望你能从中学到一些东西^_^
您可以使用 reduce flat
来提取嵌套数组。如果你通过Infinity
,不管有多深,它们都会被提取出来。
const result = flatten([1,2,[3,4],[5,6,7]]) // result: [1,2,3,4,5,6,7]
全部变成一维数组
在我的扑克应用程序中,我有一组手牌,每手牌都是随机选择的具有价值和花色的纸牌对象的数组:
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
为了准备评估手,我想使用 Array.reduce 到 return 手对象数组。所以输出将是:
[
{
values: [5, 4, 6, 11, 12],
suits: ['s', 's', 'c', 'd', 'c']
},
{
values: [9, 12, 8, 12, 2],
suits: ['d', 'h', 'c', 's', 's']
},
{
values: [4, 6, 10, 3, 7],
suits: ['h', 's', 'c', 'd', 'd']
}
]
我尝试用嵌套的 forEach 实现它,但它失败了,我不知道为什么。我有两个 console.log,其中的输出符合预期,但最终 hands 与输入相同。
let temp = []
hands.forEach((el) => {
temp = el
el = {}
el.values = []
el.suits = []
console.log(el) //expected output
temp.forEach((obj) => {
el.values.push(obj.value)
el.suits.push(obj.suit)
console.log(el) //expected output
})
})
console.log(hands) //same as original
好了 - 使用嵌套 Array.prototype.reduce
函数的解决方案:
var array=[[{value:5,suit:'s'},{value:4,suit:'s'},{value:6,suit:'c'},{value:11,suit:'d'},{value:12,suit:'c'}],[{value:9,suit:'d'},{value:12,suit:'h'},{value:8,suit:'c'},{value:12,suit:'s'},{value:2,suit:'s'}],[{value:4,suit:'h'},{value:6,suit:'s'},{value:10,suit:'c'},{value:3,suit:'d'},{value:7,suit:'d'}]];
var result = array.reduce(function(p, c) {
p.push(c.reduce(function(a, b) {
a.values.push(b.value);
a.suits.push(b.suit);
return a;
}, {values: [],suits: []}));
return p;
},[]);
console.log(result);
.as-console-wrapper {top: 0;max-height: 100%!important;}
这是一个使用 string concat
和 reduce
的简单解决方案。你可以尝试这样的事情:
var reduced = [];
//here a is your initial array
for(var i=0; i<a.length;i++){
reduced.push(a[i].reduce(function(prev,curr){
var obj={value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj}));
}
console.log(reduced)
编辑:根据@Barmar 评论这个returns 字符串。如果你想要一个数组,你可以这样做:
for(var i=0; i<a.length;i++){
var tempElm =a[i].reduce(function(prev,curr) {
var obj= {value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj});
tempElm['value'] = tempElm['value'].split();
tempElm['suit']= tempElm['suit'].split();
reduced.push(tempElm);
}
console.log(reduced)
编辑 2: 由于对上述修复的公平批评(增加了将字符串转换为数组的开销),您可以直接创建数组,如下所示:
var reduced = [];
for(var i=0; i<a.length;i++){
var valArray = []; var suitArray=[];
var tempElm = a[i].reduce(function(prev,curr) {
valArray.push(curr.value);suitArray.push(curr.suit);
var obj= {value:valArray,suit:suitArray};
return obj;
},null);
console.log(reduced)
您必须考虑输入数据 (DATA
) 和输出 (DATA'
)
注意 1:1 HAND
和 HAND'
之间的关系意味着我们将使用 Array.prototype.map
进行一次转换。另一方面,CARD
与 HAND'
有 N:1 关系,这意味着我们将使用 Array.prototype.reduce
进行转换
所以在我们工作的时候请记住,我们将做一个 map 和一个 reduce
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
let output =
data.map(cards =>
cards.reduce(({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
}), {values: [], suits: []}))
console.log(output)
现在当然看起来有点密集,所以如果我们能稍微降低复杂性就好了。通过为 map
和 reduce
制作一些柯里化适配器,我们可以表达一个可以很好地执行转换的函数
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
const map = f => xs => xs.map(f)
const reduce = f => y => xs => xs.reduce(f, y)
const handAppendCard = ({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
})
const makeHands =
map (reduce (handAppendCard) ({values:[], suits:[]}))
let output = makeHands (data)
console.log(output)
这只是解决问题的一种方法。希望你能从中学到一些东西^_^
您可以使用 reduce flat
来提取嵌套数组。如果你通过Infinity
,不管有多深,它们都会被提取出来。
const result = flatten([1,2,[3,4],[5,6,7]]) // result: [1,2,3,4,5,6,7]
全部变成一维数组