Example #1
0
def divide_to_slices(sequence, n_slices):
    '''
    Divide a sequence to slices.
    
    Example:
    
        >>> divide_to_slices(range(10), 3)
        [range(0, 4), range(4, 7), range(7, 10)]
        
    '''
    from combi._python_toolbox import cute_iter_tools

    assert isinstance(n_slices, numbers.Integral)
    assert n_slices >= 1

    sequence_length = get_length(sequence)
    base_slice_length, remainder = divmod(sequence_length, n_slices)
    indices = [0]
    for i in range(n_slices):
        indices.append(indices[-1] + base_slice_length + (remainder > i))
    assert len(indices) == n_slices + 1
    assert indices[0] == 0
    assert indices[-1] == sequence_length
    return [
        sequence[x:y]
        for x, y in cute_iter_tools.iterate_overlapping_subsequences(indices)
    ]
Example #2
0
def divide_to_slices(sequence, n_slices):
    '''
    Divide a sequence to slices.
    
    Example:
    
        >>> divide_to_slices(range(10), 3)
        [range(0, 4), range(4, 7), range(7, 10)]
        
    '''
    from combi._python_toolbox import cute_iter_tools
    
    assert isinstance(n_slices, numbers.Integral)
    assert n_slices >= 1
    
    sequence_length = get_length(sequence)
    base_slice_length, remainder = divmod(sequence_length, n_slices)
    indices = [0]
    for i in range(n_slices):
        indices.append(indices[-1] + base_slice_length + (remainder > i))
    assert len(indices) == n_slices + 1
    assert indices[0] == 0
    assert indices[-1] == sequence_length
    return [sequence[x:y] for x, y in
                     cute_iter_tools.iterate_overlapping_subsequences(indices)]
Example #3
0
def all_equivalent(iterable, relation=operator.eq, *, assume_reflexive=True,
                   assume_symmetric=True, assume_transitive=True):
    '''
    Return whether all elements in the iterable are equivalent to each other.
    
    By default "equivalent" means they're all equal to each other in Python.
    You can set a different relation to the `relation` argument, as a function
    that accepts two arguments and returns whether they're equivalent or not.
    You can use this, for example, to test if all items are NOT equal by
    passing in `relation=operator.ne`. You can also define any custom relation
    you want: `relation=(lambda x, y: x % 7 == y % 7)`.
    
    By default, we assume that the relation we're using is an equivalence
    relation (see http://en.wikipedia.org/wiki/Equivalence_relation for
    definition.) This means that we assume the relation is reflexive, symmetric
    and transitive, so we can do less checks on the elements to save time. You
    can use `assume_reflexive=False`, `assume_symmetric=False` and
    `assume_transitive=False` to break any of these assumptions and make this
    function do more checks that the equivalence holds between any pair of
    items from the iterable. (The more assumptions you ask to break, the more
    checks this function does before it concludes that the relation holds
    between all items.)
    '''
    from combi._python_toolbox import sequence_tools
    
    if not assume_transitive or not assume_reflexive:
        iterable = sequence_tools.ensure_iterable_is_sequence(iterable)
        
    if assume_transitive:
        pairs = cute_iter_tools.iterate_overlapping_subsequences(iterable)
    else:
        from combi._python_toolbox import combi
        pairs = tuple(
            iterable * comb for comb in combi.CombSpace(len(iterable), 2)
        )
        # Can't feed the items directly to `CombSpace` because they might not
        # be hashable.
        
    if not assume_symmetric:
        pairs = itertools.chain(
            *itertools.starmap(lambda x, y: ((x, y), (y, x)), pairs)
        )
    
    if not assume_reflexive:
        pairs = itertools.chain(pairs,
                                zip(iterable, iterable))
        
    return all(itertools.starmap(relation, pairs))
Example #4
0
def find_clear_place_on_circle(circle_points, circle_size=1):
    '''
    Find the point on a circle that's the farthest away from other points.
    
    Given an interval `(0, circle_size)` and a bunch of points in it, find a
    place for a new point that is as far away from the other points as
    possible. (Since this is a circle, there's wraparound, e.g. the end of the
    interval connects to the start.)
    '''

    from combi._python_toolbox import cute_iter_tools

    # Before starting, taking care of two edge cases:
    if not circle_points:
        # Edge case: No points at all
        return circle_size / 2
    if len(circle_points) == 1:
        # Edge case: Only one point
        return (circle_points[0] + circle_size / 2) % circle_size

    sorted_circle_points = sorted(circle_points)
    last_point = sorted_circle_points[-1]
    if last_point >= circle_size:
        raise Exception("One of the points (%s) is bigger than the circle "
                        "size %s." % (last_point, circle_size))
    clear_space = {}

    for first_point, second_point in \
        cute_iter_tools.iterate_overlapping_subsequences(sorted_circle_points,
                                                     wrap_around=True):

        clear_space[first_point] = second_point - first_point

    # That's the only one that might be negative, so we ensure it's positive:
    clear_space[last_point] %= circle_size

    maximum_clear_space = max(clear_space.values())

    winners = [
        key for (key, value) in clear_space.items()
        if value == maximum_clear_space
    ]

    winner = winners[0]

    result = (winner + (maximum_clear_space / 2)) % circle_size

    return result
Example #5
0
def find_clear_place_on_circle(circle_points, circle_size=1):
    '''
    Find the point on a circle that's the farthest away from other points.
    
    Given an interval `(0, circle_size)` and a bunch of points in it, find a
    place for a new point that is as far away from the other points as
    possible. (Since this is a circle, there's wraparound, e.g. the end of the
    interval connects to the start.)
    '''

    from combi._python_toolbox import cute_iter_tools

    # Before starting, taking care of two edge cases:
    if not circle_points:
        # Edge case: No points at all
        return circle_size / 2
    if len(circle_points) == 1:
        # Edge case: Only one point
        return (circle_points[0] + circle_size / 2) % circle_size
    
    sorted_circle_points = sorted(circle_points)
    last_point = sorted_circle_points[-1]
    if last_point >= circle_size:
        raise Exception("One of the points (%s) is bigger than the circle "
                        "size %s." % (last_point, circle_size))
    clear_space = {}
    
    for first_point, second_point in \
        cute_iter_tools.iterate_overlapping_subsequences(sorted_circle_points,
                                                     wrap_around=True):
        
        clear_space[first_point] = second_point - first_point
        
    # That's the only one that might be negative, so we ensure it's positive:
    clear_space[last_point] %= circle_size
    
    maximum_clear_space = max(clear_space.itervalues())
    
    winners = [key for (key, value) in clear_space.iteritems()
               if value == maximum_clear_space]
    
    winner = winners[0]
    
    result = (winner + (maximum_clear_space / 2)) % circle_size
    
    return result