# Increase efficiency of card-ordering program

As mentioned in @rolfl comment. What this program does is that it "resequences the cards using a fixed system and count the number of times the resequencing happens before the output is the same as the input."

I was wondering how I could make this program faster or perhaps use less memory. I thought about using dictionaries instead of lists as they have faster look ups. I'm not sure how to decrease the memory size of this program.

num_cards = input("Please enter the number of cards in the deck: ")

def num_of_round(num_cards):
rounds = 0
orig_order = range(1,num_cards + 1)
card_list  = list(orig_order)
table_list = []

while 1:
while len(card_list) > 0:
table_list.append(card_list[0])     # STEP 1:   add top card to table
card_list.remove(card_list[0])      #           remove top card from deck
if len(card_list) == 0:
break
card_list.append(card_list[0])                  # STEP 2:   after removal of card, put top card on bottom of deck
card_list.remove(card_list[0])                  #           update ordering of deck
rounds += 1                                         # a round has passed
table_list.reverse()
card_list, table_list = table_list, card_list
if card_list == orig_order:
break
print rounds

num_of_round(num_cards)

• Is this 'shuffle' code? It appears to resequence the cards using a fixed system and count the number of times the resequencing happens before the output is the same as the input.... right? – rolfl Nov 18 '13 at 2:22
• @rolfl yes it is – Liondancer Nov 18 '13 at 2:23
• Sounds like if you wanted to, you could reduce this to essentially no memory, and no time, by working out what the function is that describes the problem, and then just do the math rather than doing the actual work – rolfl Nov 18 '13 at 2:27
• @rolfl that is something I also considered. I thought it would be too hard to come up with a formula to compute this. – Liondancer Nov 18 '13 at 2:31

Here is a good opportunity to break out a couple of tools from the standard library.

collections.deque offers fast appends and pops on both ends and is thus perfect to represent your deck of cards, when you take cards from the top and put some back to the bottom.

itertools.cycle can be used to switch between the two destinations of the cards: the top of the pile (table_list.appendleft) and the bottom of the deck (card_list.append). Using appendleft there avoids the need to reverse the pile each round.

Also, a while True loop with a round += 1 inside could be a for round ... loop instead.

from collections import deque
from itertools import cycle, count

def num_of_round(num_cards):
orig_order = deque(xrange(num_cards))
card_list  = deque(orig_order)
table_list = deque()

for rounds in count(1):
appendfunc = cycle((table_list.appendleft, card_list.append))
while card_list:
append = next(appendfunc)
append(card_list.popleft())
card_list, table_list = table_list, card_list
if card_list == orig_order:
return rounds