最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Array.reduce on a multidimensional array to array of objects - Stack Overflow

programmeradmin4浏览0评论

In my poker app I have an array of hands, each hand being array of randomly selected card objects with value and suit:

[ [ { 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' } ] ]

To prepare the hands for evaluation I want to use Array.reduce to return an array of hand objects. So the output would be:

[ 
  { 
    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'] 
  } 
]

I tried implementing this with nested forEach's, but its failing and I don't know why. I have two console.log's within which output as expected, but in the end hands is identical to the input.

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

In my poker app I have an array of hands, each hand being array of randomly selected card objects with value and suit:

[ [ { 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' } ] ]

To prepare the hands for evaluation I want to use Array.reduce to return an array of hand objects. So the output would be:

[ 
  { 
    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'] 
  } 
]

I tried implementing this with nested forEach's, but its failing and I don't know why. I have two console.log's within which output as expected, but in the end hands is identical to the input.

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
Share Improve this question edited Dec 20, 2016 at 17:33 Barmar 781k56 gold badges545 silver badges659 bronze badges asked Dec 20, 2016 at 1:12 Jackson LenhartJackson Lenhart 6403 gold badges8 silver badges21 bronze badges 6
  • 4 "I want to use reduce" ... so where is your code attempt to do so? This isn't a code writing service. This site works by you posting your code that isn't working as expected and people help you fix that – charlietfl Commented Dec 20, 2016 at 1:25
  • 1 I made code attempts, I didn't think they would be helpful to post because it seemed any valid answer would be a complete rewrite of my implementation. Fair criticism though, I'll keep it in mind. – Jackson Lenhart Commented Dec 20, 2016 at 1:32
  • But you are also missing the point that you learn from your mistakes. Give a man a fish, or teach a man to fish – charlietfl Commented Dec 20, 2016 at 1:35
  • 1 Why does this have to be done using reduce? It seems like it would be simpler using forEach. – Barmar Commented Dec 20, 2016 at 2:02
  • 1 el is a variable local to the function, it gets reset to {} each time through the forEach loop. Your code never modifies hands. – Barmar Commented Dec 20, 2016 at 17:35
 |  Show 1 more comment

4 Answers 4

Reset to default 16

You have to be thinking about the shape of your input data (DATA) and output (DATA')

Note 1:1 relationship between HAND and HAND' meaning we will use Array.prototype.map for one transformation. On the other hand, CARD has a N:1 relationship with HAND' meaing we will use Array.prototype.reduce for that transformation

So keep in mind while we're working, we will be doing a map and a 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)

Now of course that looks a little dense so it would be nice if we could dial down the complexity a bit. By making some curried adapters for map and reduce we can express a function that performs your transformation quite nicely

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)

That's just one way to approach the problem. I hope you were able to learn something from it ^_^

There you go - a solution using nested Array.prototype.reduce functions:

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;}

You can use reduce flat to extract nested arrays. If you pass Infinity, no matter how deep they are, they'll be extracted.

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

Everything becomes one-dimensional array

Here's a simple solution with string concat and reduce. You could try something like:

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)

EDIT: As per @Barmar comment this returns string. If you want an array you could do:

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)

EDIT 2: With the fair criticism for the above fix (which adds an over head of converting string to array) You could directly create array instead as follows:

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)
发布评论

评论列表(0)

  1. 暂无评论