1

I am trying to create a deck of 52 cards. I can create it easily with double for-loop but it has O(n2) complexity. So I was trying to play with map() and forEach() array methods but things are complex with them needing to return stuffs. Here is my code below.

(function deckCreate() {
  var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
  var suits = ["clubs", "diamonds", "hearts", "spades"];
  var newDeck = values.map(function(xValue) {
    suits.forEach(function(xSuit) {
      return [xSuit,xValue];
    });
  });
  return newDeck;
}());

It gives an array of length 13 all undefined inside. I tried swapping forEach() before map() just incase but the result was the same.

The issue I found while console.log() inside those functions was that the elements were not being mapped to each other but were printed all separately. What could be the issue be?

3
  • Could i just ask is your goal to increase speed of script execution? Commented Jan 7, 2017 at 21:06
  • You're getting undefined because .forEach doesn't return anything. Change that to .map and put a return at the beginning of that line and it should work correctly. As far as performance I'd be surprised if this took more than 1ms. Commented Jan 7, 2017 at 21:18
  • 1
    @sinisake nah just trying to learn new ways of doing rather than nested for-loops Commented Jan 7, 2017 at 21:19

4 Answers 4

1

You're not returning anything from your map function, so the implicit return value is undefined, hence your array of 13 undefined values.

suits.forEach needs to be return suits.map. This will give you an array of 13 elements, where each element is an array of four elements, where each element of the inner array is a two element [suit, value] array. You can then reduce the top-level array into the 52 element array you're after:

var newDeck = values.map(function(xValue) {
  return suits.map(function(xSuit) {
    return [xSuit,xValue];
  });
}).reduce(function (a, b) { return a.concat(b) });
Sign up to request clarification or add additional context in comments.

10 Comments

What is purpose of .reduce() call?
@guest271314 As I said: The result of map(map(...)) is a a nested array of 13(4(2)) elements. The question was how to produce a 52 element array of suit/number pairs. Reduce concatenates the 13*4 arrays into a single 52 element array. You could also pass the top-level array to Array.prototype.concat.apply and achieve the same results.
Where does text of Question describe expected result being "a 52 element array of suit/number pairs"?
@guest271314 "I am trying to create a deck of 52 cards".
@meagar you are right. i did initially with double map and got similar 13 length array with each array element having [values[0],[suits]]. i need to look at reduce() method. thanks :)
|
1

The reason you're having trouble is that you aren't returning from your outer .map() callback. Even if you did, though, [].forEach always returns undefined, regardless of what happens inside its callback.

So, since you're using forEach to iterate the inner array, you get an array of 13 undefineds from map.

What you should be using is .map() all the way down and return every step of the way:

const first = [1, 2, 3];
const second = ['a', 'b', 'c'];

const mapped = first.map(function(digit) {
  return second.map(function(letter) {
    return [digit, letter];
    });
  });

console.log(mapped);

Seeing how you're clearly trying to learn and improve yourself, I'll leave you to adjust this example to your specific case.

P.S. If you want a flattened array, have a look at [].reduce() and [].concat().

2 Comments

"return [xSuit,xValue]" Given pattern at Question should first and second be reversed at .map() calls?
@Madara Uchiha thanks senpai for the answer. i will check out reduce() method now
1

Use a simple for loop. Use suits[Math.floor(i / 13)] to get the right suit, and use the remainder operator % to get the card number for each suit:

function deckCreate() {
  var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
  var suits = ["clubs", "diamonds", "hearts", "spades"];
  var newDeck = [];

  for (var i = 0; i < 52; i++) {
    newDeck.push([suits[Math.floor(i / 13)], values[i % 13]]);
  }

  return newDeck;
}

var result = deckCreate();

console.log(result);

2 Comments

you are right. but it won't help if i want to use face-values like J,Q,K etc initially (i can change it later tho) :)
@Jamie - changed the answer to work with the original values array.
1

I think it's better to simplify it.

We know that there are just 4 suits, so it's enough to get list by suit name:

function createDeck() {
  var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
  var deck = {"clubs": values.slice(), "diamonds": values.slice(), "hearts": values.slice(), "spades": values.slice()};
  return deck;
}

var deck = createDeck();

console.log('CLUBS:', deck.clubs);
console.log('DIAMONDS:', deck.diamonds);
console.log('HEARTS:', deck.hearts);
console.log('SPADES:', deck.spades);

P.S. in my case I'll create a class that makes generation, iteration and etc stuff to easily use it.

function Deck() {
  var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
  var suits = ['clubs', 'diamonds', 'spades', 'hearts'];
  
  this.getSuits = function() {return suits.splice();}
  this.getValues = function() {return values.splice();}
  
  var asObject;
  this.asObject = function() {
    if(asObject) return asObject;
    
    asObject = {};
    suits.map(function(suit) {
      asObject[suit] = values.slice();
    });
    return asObject;
  };
  
  var asArray;
  this.asArray = function() {
    if(asArray) return asArray;
    asArray = [];
    
    suits.map(function(suit) {
      values.map(function(value) {
        asArray.push([suit, value]);
      });
    });
    return asArray;
  }
  
  this.iterate = function(fn) {
    this.asArray().map(fn);  
  }
}

var deck = new Deck();

deck.iterate(function(card) {
  console.log('CARD: ', card[0], card[1]);             
});

console.log(deck.asObject());
console.log(deck.asArray());

3 Comments

How is newDeck accessed outside of IIFE?
oh, I understand, sec, modifying
@guest271314 check now (;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.