For all of them --- not guaranteed that you'll be able to achieve the optimum..
My solution is basically a greedy algorithm: Make a list of (artist, tracks) pairs, and sort descending by len(tracks). Then iteratively: 1. Take the next track from the first artist on the list. 2. Move that artist down to position total/len(tracks). Repeat until all tracks have been selected :-) Generally it works well, except at the end of the playlist sometimes. See attachment for my implementation. (uses mmpython, which you can find on the net) -- John. On 21/10/05, Liam Clarke <[EMAIL PROTECTED]> wrote: > Hmmm, that's interesting. > > Obviously, for a playlist with x songs, and n songs by a particular > artist, the optimum separation between songs would be x/n. > > Which would be easy for one artist, but for all of them? > > Hmm... > > Let's see. First off, let's discount all the artists with only one > song, they can be the space filler. > > Next, you'd have to work out optimal spacing for each artist's songs, > and try to insert them into a list. If that slot was already taken, > you'd want to look down and up the list for the next free space, > choosing whichever maximised the distance. And you'd have to treat > x[5] - 10 as x[96] for a list x where len(x) == 100. > > Err, there's got to be an algorithm for this sorta stuff, but I can't > understand the big words when I google it... what's your solution? > > On 10/21/05, John Fouhy <[EMAIL PROTECTED]> wrote: > > Hmm, neat. I don't have any feedback for you on your code, but since > > you're working with this sort of thing, I have a puzzle for you: > > > > Suppose you have a collection of MP3 files. You want to build a > > random playlist, subject to the condition that tracks by the same > > artist are as far apart as possible. You can assume you have the > > track / artist data in any structure you like. How would you do this? > > > > (I have a solution, but I don't think it is optimal. In fact, I'm not > > sure how to actually define "optimal" here... And so I am interested > > in how other people would solve this problem :-) ) > > > > -- > > John.
import os import mmpython import random from math import log, ceil from itertools import * def getFiles(directory): """ Walk directory under root, getting a list of all regular files. """ res = [] for root, dirs, files in os.walk(directory): for f in files: res.append(os.path.join(root, f)) return res def getMusic(files): """ Filter a list of files for music files. """ return [f for f in files if os.path.splitext(f)[1][1:].lower() in ('mp3', 'ogg')] def addInfo(files): """ Add tag info to a list of files. """ return [(mmpython.parse(f), f) for f in files] def getMusicByArtist(musicInfo): """ Process a list of (taginfo, filename) pairs into a dict of artist |-> filename. """ files = {} errors = [] for info, filename in musicInfo: if not info: errors.append(filename) continue try: files[info.artist].append((info, filename)) except KeyError: files[info.artist] = [(info, filename)] return files, errors def extraRandom((musicByArtist, errors)): """ Produce a list of files with maximum gaps between artists. """ # Do some shuffling first. musicByArtist = dict(musicByArtist) for stuff in musicByArtist.values(): random.shuffle(stuff) data = musicByArtist.items() data.sort(key=lambda x: len(x[1]), reverse=True) # Total number of tracks. total = sum(len(x) for x in musicByArtist.itervalues()) # Current position in list of each artist. positions = dict(izip(musicByArtist.iterkeys(), repeat(0))) randList = [] while len(randList) < total: artist, tracks = data[0] randList.append((artist, tracks[positions[artist]])) jump = total / len(tracks) del data[0] positions[artist] += 1 if positions[artist] < len(tracks): data[jump:jump] = [(artist, tracks)] return randList, errors def copy(source, dest): f = file(dest, 'wb') f.write(file(source, 'rb').read()) f.close() def procFiles(inDir, outDir): """ Take files from structure in inDir, randomize, produce flat list of numbered tracks in outDir. """ randList, errors = extraRandom(getMusicByArtist(addInfo(getMusic(getFiles(inDir))))) files = [x[1] for x in randList] precision = int(ceil(log(len(files), 10))) for i, (info, fn) in enumerate(files): ext = os.path.splitext(fn)[1] name = '%0*d. %s - %s%s' % (precision, i, info.artist, info.title, ext) for c in '?*\'"': name = name.replace(c, '') fullname = os.path.join(outDir, name) copy(fn, fullname) if __name__ == '__main__': import sys procFiles(*sys.argv[1:])
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor