1

I'd like to create a card deck in the most efficient way. This is simple solution with double for loop and standard lists:

card = []
for figure in range(2, 15):
    for suite in [1, 2, 3, 4]:
        card = [figure, suite]
        self.cards.append(card)

This code will be executed millions of times so I'd like to optimize it using Numpy.

EDIT1: I even think whether writing down all possibilities and putting them into array won't be the fastest..

7
  • 2
    Why generate this every time? Just generate the deck once and copy it when you need it Commented Jan 31, 2019 at 19:29
  • 1
    Why does it need to executed so many times? What's different each time? The deck is just a list of 52 pairs. Commented Jan 31, 2019 at 19:30
  • 2
    list(itertools.product(range(2,15), [1,2,3,4])) is a good way of generating these 52 pairs. Commented Jan 31, 2019 at 19:32
  • Lol, just focused to much on rewriting to numpy.. Thanks guys Commented Jan 31, 2019 at 19:32
  • 1
    IF you'd like to use numpy, you could do: cards = np.mgrid[1:5,2:15] Commented Jan 31, 2019 at 19:35

1 Answer 1

3

Somebody beat me to it in the comments, but I have some timing information for you. Note that your times may vary, but relative times should be fairly representative of the performance you might see.

First your code, which I fixed to make runnable:

cards = []
for figure in range(2, 15):
    for suite in [1, 2, 3, 4]:
        card = [figure, suite]
        cards.append(card)
# 8.04 µs ± 27.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

So 8.04 microseconds is the time to beat! Using numpy.mgrid:

import numpy as np
cards = np.mgrid[1:5, 2:15]
# 20.5 µs ± 320 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Surprisingly much slower. I wonder if something isn't set up ideally on my system for numpy. I still recommend trying it on your system (use the %%timeit cell magic in a Jupyter notebook for easy profiling).

Next using itertools.product:

import itertools as it
figures = range(2, 15)
suits = [1, 2, 3, 4]
cards = list(it.product(suits, figures))
# 2.5 µs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Faster! And the best news is that it.product() returns an iterator instead of creating the list when called, so if you don't need the actual card list until later, you can defer creating the list and just pass the iterator around. Creating the iterator is the fastest by far:

cards_it = it.product(suits, figures)  # notice no 'list'
# 479 ns ± 9.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

That's 5-10 times faster than anything else!

Sign up to request clarification or add additional context in comments.

1 Comment

Great overview. I learnt a lot ways to do this thing. However this whole question is quite absurd. Why would anyone create same iterator over and over? I would understand if he wants random card deck, but this is quite absurd. I have contribution though too. Its not fastest, but also not slowest of your examples: cards=[[z,i] for i in range(1,5) for z in range(2,15)]

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.