We want to find the numbers higher or equal than 1000 that the sum of every four consecutives digits cannot be higher than a certain given value.
If the number is ``` num = d1d2d3d4d5d6 ```, and the maximum sum of 4 contiguous digits is ```maxSum```, then:
```python
d1 + d2 + d3 + d4 <= maxSum
d2 + d3 + d4 + d5 <= maxSum
d3 + d4 + d5 + d6 <= maxSum
```
For that purpose, we need to create a function, ```max_sumDig()```, that receives ```nMax```, as the max value of the interval to study (the range (1000, nMax) ), and a certain value, ```maxSum```, the maximum sum that every four consecutive digits should be less or equal to. The function should output the following list with the data detailed bellow:

```[(1), (2), (3)]```

(1) - the amount of numbers that satisfy the constraint presented above 

(2) - the closest number to the mean of the results, if there are more than one, the smallest number should be chosen.

(3) - the total sum of all the found numbers

Let's see a case with all the details:
```
max_sumDig(2000, 3) -------> [11, 1110, 12555]

(1) -There are 11 found numbers: 1000, 1001, 1002, 1010, 1011, 1020, 1100, 1101, 1110, 1200 and 2000

(2) - The mean of all the found numbers is:
      (1000 + 1001 + 1002 + 1010 + 1011 + 1020 + 1100 + 1101 + 1110 + 1200 + 2000) /11 = 1141.36363,  
      so 1110 is the number that is closest to that mean value.

(3) - 12555 is the sum of all the found numbers
      1000 + 1001 + 1002 + 1010 + 1011 + 1020 + 1100 + 1101 + 1110 + 1200 + 2000 = 12555

Finally, let's see another cases
```
max_sumDig(2000, 4) -----> [21, 1120, 23665]

max_sumDig(2000, 7) -----> [85, 1200, 99986]

max_sumDig(3000, 7) -----> [141, 1600, 220756]
```

Happy coding!!

Difficulty: introductory

Starter code:

def max_sumDig(nMax, maxSum):
	

Solutions:
def check(num,max_sum):
    l = [int(i) for i in str(num)]
    for i in range(0,len(l) - 3):
        if sum(l[i:i+4]) > max_sum:return False
    return True

def max_sumDig(nMax, maxSum):
    found = [i for i in range(1000,nMax + 1) if check(i,maxSum)]
    mean = sum(found) / float(len(found))
    for i in range(len(found) - 1):
        if abs(mean - found[i]) < abs(mean - found[i + 1]):
            mean = found[i]
            break
    return [len(found), mean, sum(found)]

def max_sumDig_aux(nmax, maxsm):
    res, i = [], 1000
    while (i <= nmax):
        a = list(str(i))
        j, b = 0, 0
        while (j <= len(a) - 4):
            if (sum(map(int, a[j:j+4])) <= maxsm):
                b += 1
            j += 1
        if (b == j):
            res.append(i)
        i += 1
    return res
    
def max_sumDig(nmax, maxsm):
    res = max_sumDig_aux(nmax, maxsm)
    l = len(res)
    s = sum(res)
    m = s / float(l)
    d = list([(abs(x - m), x) for x in res])
    d.sort()
    return [l, d[0][1], s]


def max_sumDig(nMax, maxSum):
    answers = []
    
    for i in range(1000, nMax + 1):
        good = True
        n = [int(x) for x in str(i)]
        for j in range(0, len(n)-3):
            if sum([n[j],n[j+1],n[j+2],n[j+3]]) > maxSum:
                good = False
        if good == True:
            answers.append(i)
    
    num, tot = len(answers), sum(answers)
    return [num, min(answers, key=lambda x: abs(x-(tot/float(num)))), tot]

from statistics import mean

def max_sumDig(nMax, maxSum):
    def okay(x):
        L = list(map(int, str(x)))
        return all(sum(t) <= maxSum for t in zip(L, L[1:], L[2:], L[3:]))
    result = list(filter(okay, range(1000, nMax+1)))
    m = mean(result)
    return [len(result), min(result, key=lambda x:abs(x-m)), sum(result)]

from bisect import bisect

def max_sumDig(n_max, max_sum):
    numbers = []
    
    for n in range(1000, n_max +1):
        s = str(n)
        if all(sum(map(int, s[i:i+4])) <= max_sum for i in range(len(s)-3)):
            numbers.append(n)
    
    res_sum   = sum(numbers)
    res_count = len(numbers)
    res_avg   = 1.0 * res_sum / res_count
    
    idx = bisect(numbers, res_avg)
    a, b = numbers[idx-1 : idx+1]
    closest = a if res_avg - a <= b - res_avg else b
    
    return [ res_count, closest, res_sum ]


def sum_int(i):
    """Sum digits of an integer - standard"""
    s=0
    while i != 0:
        s += i % 10
        i //= 10
    return s

def find_4digs(m,MaxNum,MaxSum):
    """start by finding all 4 digit numbers n m \leq n \leq MaxNum with sum \leq MaxSum"""
    
    sts=[m]
    for i in range(0, 4):
        for st in sts:            
            while (sum_int(st+10**i)<= MaxSum and st+10**i <= MaxNum):
                sts.append(st+10**i)
                st += 10**i
    sts=list(set(sts)) # delete duplicates
    return (sts)

def find_5digs(nums,MaxNum,MaxSum):
    """ takes in a list of 4 digit numbers \leq MaxNum and with sum \leq MaxSum. Returns list of 4 and 5 digit nums 
    with every consecutive 4 digits satisfying the same conditions"""
    #TODO: Generalize to x digit numbers
    
    for s in  nums:
        # add digits before the 4 digit nums
        for i in range(1, MaxSum - sum_int(int(str(s)[0:3]))+1):
            cand1 = int(str(i)+str(s))
            if cand1 <= MaxNum:
                nums.append(cand1)
        # add digits after the 4 digit nums
        for i in range(0,MaxSum-sum_int(int(str(s)[1:4]))+1):
            cand2 = int( str(s) + str(i) )
            if cand2 <= MaxNum:
                nums.append(cand2)    

    nums=list(set(nums)) # delete duplcates
    return nums
    
def max_sumDig(MaxNum,MaxSum):
    """ Find all numbers satisfying the conditions. """
    
    nums = find_4digs(1000,MaxNum,MaxSum)
    nums = find_5digs(nums,MaxNum,MaxSum)
    
    # calcualte min distance from mean
    mean = sum(nums)/len(nums)           
    dists=[ abs(s-mean) for s in nums] 
    
    for i in range(len(dists)):
        if dists[i] == min(dists):
            min_dist=nums[i]   
            
    return [len(nums), min_dist, sum(nums)]


def max_sumDig(nMax, maxSum):
    
    def isGood(s):  return all(sum(map(int, str(s[i:i+4]))) <= maxSum for i in range(len(s)-3) )
    
    lst = [n for n in range(1000, nMax+1) if isGood(str(n))]
    s, l = sum(lst), len(lst)
    avg = 1.0*s/l
    iAvg = next( i for i,n in enumerate(lst) if n > avg )
    nearest = sorted(lst[iAvg-1:iAvg+1], key=lambda n: abs(n-avg))[0]
    return [l, nearest, s]

def x(i, maxSum): #check if number satisfies requirments
    s = str(i)
    for i in range(len(s)-3):
        if sum(map(int,list(s[i:i+4])))>maxSum:
            return False
    return True

def max_sumDig(nMax, maxSum):
    count = 0
    sum_ = 0 
    mean_ = 0
    _3 = None
    
    for i in range(1000, nMax+1):
        if x(i, maxSum):
            count += 1
            sum_ += i
            if not _3: _3 = i
    
    mean_ = float(sum_)/count
    _3 = i
    for i in range(1000, nMax+1):
        if x(i, maxSum):
            if  abs(i - mean_) < abs(_3 - mean_): _3 = i 
    
    return [count, _3, sum_]

def max_sumDig(nMax, maxSum):
    count=0
    nums=[]
    if len(str(nMax)) == 4:
        for i in range(1000, nMax+1):
            if ( (i%10) + ( (i//10) % 10 ) + ( (i//100) % 10 ) + ( (i//1000) % 10 )) <= maxSum:
                nums.append(i)
                count+=1
    elif len(str(nMax)) == 5:
        for i in range(1000, nMax+1):
            if ( (i%10) + ( (i//10) % 10 ) + ( (i//100) % 10 ) + ( (i//1000) % 10 )) <= maxSum and (( (i//10) % 10 ) + ( (i//100) % 10 ) + ( (i//1000) % 10 ) + ( (i//10000) % 10 )) <= maxSum:
                nums.append(i)
                count+=1
    elif len(str(nMax)) == 6:
        for i in range(1000, nMax+1):
            if ( (i%10) + ( (i//10) % 10 ) + ( (i//100) % 10 ) + ( (i//1000) % 10 )) <= maxSum and (( (i//10) % 10 ) + ( (i//100) % 10 ) + ( (i//1000) % 10 ) + ( (i//10000) % 10 )) <= maxSum and (( (i//100) % 10 ) + ( (i//1000) % 10 ) + ( (i//10000) % 10 ) + ( (i//100000) % 10 )) <= maxSum:
                nums.append(i)
                count+=1
    media=sum(nums)/len(nums)
    for n in nums:
        if media <= n:
            if (n - media) > (media - nums[nums.index(n)-1]):
                media=nums[nums.index(n)-1]
                break
            else:
                media=n
                break
    suma=sum(nums)
    return [count, media, suma]