views:

364

answers:

5

Hi,

I am wondering if there is a "best" way to shuffle a list of elements that contains duplicates such that the case where array[i] == array[i+1] is avoided as much as possible.

I am working on a weighted advertising display (I can adjust the number of displays per rotation for any given advertiser) and would like to avoid the same advertister appearing twice in a row.

A: 

What's the biggest number of duplicates you may have? 2, 3, any?

MK_Dev
Well because of the weighting e.g. advertiser 1 could appear 5 times per rotation there could be 5 duplicates easily.
Graphain
+1  A: 

Personally I think the easiest way to hand this would be to randomize the array, and then iterate over it until you find 2 elements with the same value that are next to each other. When you find 2 of the same values beside eachother, move the later one to another spot in the array by iterating over the array until you find a spot such that it isn't beside another of the same value. If you can't find a value, just leave it where it is, and continue on with the next element of the array. This probably won't be the most optimal solution, but will be fine for smaller data sets, and probably the simplest to program.

Kibbee
hmm, could be okay but that's what up to O(n^2) ?
Graphain
Probably about O(n^2), but the average case would probable be a lot lower if you don't expect a lot of duplicates.
Kibbee
Yeah, and the algorithm is straight-forward at least - can always optimise later. Wish they'd taught us shuffle problems at uni though.
Graphain
The very worst case would be O(n^2), but I wouldn't expect you to get there with a random shuffle. Your average case is going to be close to O(n).
Bill the Lizard
Jeff has a good post on shuffling here -> http://www.codinghorror.com/blog/archives/001008.html
Bill the Lizard
+2  A: 

This is pretty similar to this question. If you replace A, B, and C in the example given over there with your advertisers, I think you arrive at the same problem. Maybe some of the solutions suggested for that one can help you.

Bill the Lizard
thanks :-) and nice rep - you have a letter!
Graphain
You're welcome. You'll get one too, when you reack 10k. :)
Bill the Lizard
+1  A: 
Loki
Nice post :-) Thanks
Graphain
A: 

For reference, my (very) naive approach was something like this (actually using LINQ/SQL calls but this is simplified):

var advertisers = getAdvertisers();
var returnList = new List();
int totalWeight = sumOfAllAdvertisersWeight();
while (totalWeight > 0)
{
    for (int i=0; i<advertisers.Count; i++)
    {
        if (advertisers[i].Weight > 0)
        {
            returnList.add(advertisers[i]);
            advertisers[i].Weight--;
            totalWeight--;
        }
    }
}
return returnList;

This will avoid duplicates until the end but yeah it would pay to check backwards through the returnList afterwards and if there are any duplicates tailing, try and place them in the mix earlier.

Graphain
There is a typo in the if conditional.
Svante