Array.reduce 将多维数组转换为对象数组

Posted

技术标签:

【中文标题】Array.reduce 将多维数组转换为对象数组【英文标题】:Array.reduce on a multidimensional array to array of objects 【发布时间】:2017-05-05 03:31:45 【问题描述】:

在我的扑克应用程序中,我有一组手牌,每手牌都是随机选择的具有价值和花色的卡片对象数组:

[ [  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 返回手部对象数组。所以输出将是:

[ 
   
    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,其中的输出符合预期,但最终手与输入相同。

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

【问题讨论】:

"我想使用 reduce" ...那么您的代码在哪里尝试这样做?这不是代码编写服务。此网站的工作原理是您发布 您的代码 无法按预期工作,人们会帮助您解决该问题 我进行了代码尝试,但我认为它们对发布没有帮助,因为似乎任何有效的答案都将完全重写我的实现。不过,公平的批评,我会记住的。 但是您也错过了从错误中吸取教训的要点。 授人以鱼,或授人以渔 为什么必须使用reduce 来完成这项工作?使用forEach 似乎会更简单。 el 是函数的局部变量,每次通过forEach 循环它都会重置为。你的代码永远不会修改hands 【参考方案1】:

您必须考虑输入数据 (DATA) 和输出 (DATA') 的形状

注意HANDHAND' 之间的1:1 关系意味着我们将使用Array.prototype.map 进行一次转换。另一方面,CARDHAND' 具有 N:1 关系,这意味着我们将使用 Array.prototype.reduce 进行该转换

所以请记住,在我们工作的时候,我们会做一个ma​​p和一个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)

当然,现在看起来有点密集,所以如果我们可以稍微降低复杂性就更好了。通过为mapreduce 制作一些柯里化适配器,我们可以表达一个可以很好地执行转换的函数

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)

这只是解决问题的一种方法。我希望你能从中学到一些东西^_^

【讨论】:

【参考方案2】:

你去 - 使用嵌套 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;

【讨论】:

【参考方案3】:

您可以使用reduce flat 来提取嵌套数组。如果你通过Infinity,不管多深都会被提取出来。

const result = flatten([1,2,[3,4],[5,6,7]]) // result: [1,2,3,4,5,6,7]

一切都变成一维数组

【讨论】:

【参考方案4】:

这是string concatreduce 的简单解决方案。您可以尝试以下方法:

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 评论,这将返回字符串。如果你想要一个数组,你可以这样做:

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)

【讨论】:

他希望结果中包含数组,而不是串联的字符串。 @Barmar 感谢您的评论...编辑了帖子以反映更改 这是一个愚蠢的修复。既然可以一开始就创建一个数组,为什么还要先创建一个字符串然后拆分成一个数组? @Barmar 这是一个中肯的评论。查看编辑 2,然后带上你得到的东西 :D ...

以上是关于Array.reduce 将多维数组转换为对象数组的主要内容,如果未能解决你的问题,请参考以下文章

reduce()方法:求和求乘积数组中每个元素出现的次数去重二维和多维数组转为一维数组

如何将多维数组转换为json对象[关闭]

对象值的Javascript数组转换为多维数组

如何将多维数组转换为Laravel中的集合

在 PHP 中将多维数组转换为 XML 对象 [重复]

将多维数组转换为一维数组的算法