[Tutor] Creating lists with 3 (later4) items occuring only once

marcus lütolf marcus.luetolf at bluewin.ch
Sat Sep 26 15:14:54 CEST 2015


Hello Martin,
again thanks for your endeavour, ist tought me to really think deeply how to
specify my task fort he Python language.
Before I start to work with your "heavy" piece of code for a beginner below
I like to make the following statements:

1. my task is to create lists or tupleS (whichever works best) containing 3
letters, later to be assigned names, in unique sequences.

2. My first approach with pairs like 'a b', 'a c',..... does not work  with
itertools.combinations(s, 3):  Although,   it produces  lists/tuples with 3
pairs
there are 4 letters in each list/tuple whereas I need only 3.

3. Therfore, I'am working with single letters creating  lists/tuples with 3
letters: ('a', 'b', 'c'), ('a','b','d')........ 
Using all 26 letters of the alphabet would correspond to Problem A:
Impossible to handle.
Using only 15 letters would already create 455 lists/tuples.
So I am using 9 letters which is practical for one letter or name can be
combined with 2 others 5 times  or on 5 days, each letter/name can occur
only once a day.
The 9 letters produce 84 lists/tuples.  But if I am isolating lists/tuple
with unique sequences by hand I am left with 15 lists/tuples but with a
uneven distrubution of the 9 letters:
a 8
b 5
c 6
d 5
e 6
f 6
g 4
h 4
i 4
This variance gets the  smaller the more letters are used.

4. I have come to the conclusion that my task is too mathematical for
itertools.  I hope I can be successfull with your code below
although it  will me take time to comprehend it.

Sorry for this long text, regards, Marcus.


-----Ursprüngliche Nachricht-----
Von: Martin A. Brown [mailto:martin at linux-ip.net] 
Gesendet: Dienstag, 22. September 2015 03:10
An: marcus lütolf <marcus.luetolf at bluewin.ch>
Cc: tutor at python.org
Betreff: Re: [Tutor] Creating lists with 3 (later4) items occuring only once


Marcus,

I have more questions for you, as well as a possible solution (though it's a
bit more verbose than I would have liked to offer).

Question:

   Problem A:  Are you looking to identify the complete set of
   possible options for constructing the triples of pairs?

   Problem B: Are you looking only to construct one set that
   satisfies the problem? [see my lousy solution]

You may observe that the question I ask is quite similar to the question
asked by Francesco [0].

If you are asking about the complete set of possible options (Problem A),
then I submit to you that you are asking a mathematical question, not a
Python question.  If that's the case, perhaps you should look further into
the Steiner system and/or ask again on the list.

If you are asking about finding an individual solution satisfying the
constraints, I submit to you that either my approach or Francesco's approach
could work for you.  If that's the case, then using random.sample may offer
you some help.  See my sample, below--it should work on Python 2.x or Python
3.x.

Comments:

   * There are rules in your system about when a player can play
     again.  The rules were not fully clear to me, so I allowed
     players to be selecteda second time, if there were no more
     players who had not already been chosen.

   * This program produces only one possible scenario for 7
     rounds of 3 distinct, simultaneously played 2-player games.
     No player can play twice in the same round.  (Simple arithmetic
     determines the minimum number of players.)

If your question is Problem A, then I wonder if you know anybody who knows
combinatorics?  I do not.

-Martin

  [0] https://mail.python.org/pipermail/tutor/2015-September/106820.html


#! /usr/bin/python

from __future__ import print_function

import sys
import string
import random
import logging

logging.basicConfig(stream=sys.stderr, level=logging.INFO) logger =
logging.getLogger()


class NotEnoughPlayers(Exception):
     pass


def choose_game_participants(players, pcount=2):
     '''returns a tuple of players for a single game
     '''
     if len(players) < pcount:
         raise NotEnoughPlayers("not enough players, need %d, have only %d:
%r" %
                                (pcount, len(players), players))
     game = tuple(sorted(random.sample(players, pcount)))
     return game


def choose_match_games(players, pcount=2, gcount=3):
     '''returns a list of games where no player is duplicated
     '''
     mcount = pcount * gcount
     if len(players) < mcount:
         raise NotEnoughPlayers("not enough players, need %d, have only %d:
%r" %
                                (mcount, len(players), players))
     eligible_players = random.sample(players, mcount)
     match = list()
     while eligible_players:
         m = choose_game_participants(eligible_players, pcount)
         for x in m:
             eligible_players.remove(x)
         match.append(m)
     match.sort()  # optional
     return match


def generate_rounds(players, pcount, gcount, rcount):
     games = set()
     matches = list()
     mcount = pcount * gcount
     eligible_players = list(players)
     if mcount > len(eligible_players):
         raise NotEnoughPlayers("not enough players (%d) to guarantee %d
%d-player games per match" %
                                (len(eligible_players), gcount, pcount))
     r = 1
     while r <= rcount:
         try:
             proposed_match = choose_match_games(eligible_players, pcount,
gcount)
         except NotEnoughPlayers:
             logger.info("adding %d additional players in round %d to meet
minimum pool requirements",
                         mcount, r)
             how_many = mcount - len(eligible_players)
             eligible_players.extend(random.sample(players, how_many))
             continue
         already_played = games.intersection(set(proposed_match))
         if already_played:
             logger.info("discarding %d %r because %r have already played",
                         r, proposed_match, list(already_played))
             continue
         else:
             games.update(proposed_match)
             matches.append(proposed_match)
             logger.info('Proposed match %r', proposed_match)
             for game in proposed_match:
                 for player in game:
                     eligible_players.remove(player)
         r = r + 1
     return matches


def log_match_info(matches, detail=False):
     for mnum, match in enumerate(matches, 1):
         logger.info("match summary %d: %r", mnum, match)
         for gnum, game in enumerate(match, 1):
             if not detail:
                 continue
             logger.info("match detail %d, game %d: players %r",
                         mnum, gnum, game)


def log_match_summary(matches):
     log_match_info(matches, detail=False)


def log_match_detail(matches):
     log_match_info(matches, detail=True)


if __name__ == '__main__':
     players = list(string.ascii_uppercase)
     random.shuffle(players)
     # players = set('ABCDEFGHIJ')
     pcount = 2                              # players per game
     gcount = 3                              # games per match
     rcount = 7                              # rounds (of matches)
     matches = generate_rounds(players, pcount, gcount, rcount)
     log_match_detail(matches)

# -- end of file


--
Martin A. Brown
http://linux-ip.net/


---
Diese E-Mail wurde von Avast Antivirus-Software auf Viren geprüft.
https://www.avast.com/antivirus



More information about the Tutor mailing list