import random

try:
    set
except:
    from sets import Set as set

def _get_value(obj, attr):
    if not attr:
        return obj
    elif isinstance(obj, dict):
        return obj[attr]
    else:
        return getattr(obj, attr)

def all_are_duplicates(items, attr=None):
    """Returns True if all given items has the same value for a given attribute"""
    return len(set([_get_value(item, attr) for item in items])) == 1

def real_shuffle(l, attr=None, remove_duplicates=False):
    """This function make a 'real' shuffle of a list, without only depend on a
    randomized shuffling but looping along the list to make sure they aren't
    repeating a given attribute."""

    # Make a copy of the list
    ret = list(l)

    # Just returns it if has 1 or less items
    if len(ret) <= 1:
        return ret

    # Randomic shuffling
    random.shuffle(ret)

    # Loop along the list to make 'real' shuffle
    new_list = []
    while not all_are_duplicates(ret, attr):
        for cur_index in range(len(ret)):
            if not new_list or _get_value(ret[cur_index], attr) != _get_value(new_list[-1], attr):
                new_list.append(ret.pop(cur_index))
                break

    new_list += ret

    # Remove the duplicates
    if remove_duplicates:
        while len(new_list) > 1 and  _get_value(new_list[-1], attr) == _get_value(new_list[-2], attr):
            new_list.pop(-1)

    return new_list

if __name__ == '__main__':
    class Animal(object):
        name = str()
        kind = str()

        def __init__(self, name, kind):
            self.name, self.kind = name, kind

        def __str__(self):
            return '%s/%s'%(self.name, self.kind)

    animals = [
        Animal('a1', 'lion'),
        Animal('b1', 'tiger'),
        Animal('a2', 'lion'),
        Animal('a3', 'lion'),
        Animal('a5', 'lion'),
        Animal('c1', 'lion'),
        Animal('a4', 'lion'),
        Animal('b2', 'tiger'),
        Animal('b3', 'tiger'),
        Animal('a6', 'lion'),
        Animal('c2', 'cat'),
        Animal('b4', 'tiger'),
    ]

    print all_are_duplicates(animals, 'kind'), all_are_duplicates(animals[2:5], 'kind')

    print '\n\nOriginal:'
    print '  ', ', '.join(map(str, animals))

    print '\n\nShuffled by Python'
    animals2 = list(animals)
    random.shuffle(animals2)
    print '  ', ', '.join(map(str, animals2))

    print '\n\nShuffled by me'
    animals3 = real_shuffle(animals, 'kind')
    print '  ', ', '.join(map(str, animals3))

    print '\n\nShuffled by me - removing duplicates'
    animals3 = real_shuffle(animals, 'kind', True)
    print '  ', ', '.join(map(str, animals3))

    print '\n\n'