How can I efficiently generate the shortest list of arguments for the range() function that will generate a given list of integers?
I'm assuming the input does not have duplicates, e.g. not [1, 2, 2, 5].



No, an efficient (polynomial time) algorithm does not exist to our best knowledge, as per "Covering a set with arithmetic progressions is NP-complete" by Lenwood S.Health.

But we can make a recursive algorithm regardless, it will just be exponential time as our input grows.

Note that the first element not covered by previous ranges must be the start of the next range. Furthermore, you can always cover at least two elements with each range. And even better, the second element you choose to cover with a range also fully determines that range. The stop condition doesn't really matter - you'd just stop when the next element generated wouldn't be in the set.

With this information you can write a recursive algorithm (which assumes l is given sorted):

def cover_ap(l):
    if not l: return []
    if len(l) == 1: return [(l[0], l[0])]

    candidates = []
    a = l[0]
    for b in l[1:]:
        ap = [a, b]
        step = b - a
        k = b + step
        while step &gt; 0 and k in l:
            ap.append(k)
            k += step
        stop = ap[-1] + 1

        remain = sorted(set(l) - set(ap))
        candidates.append([(a, stop, step)] + cover_ap(remain))

    return min(candidates, key=len)