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!!

Source: codewars | Difficulty: EASY
Tags: Fundamentals

Data structures

Mathematics

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):
	s = 0
	while i != 0:
		s += i % 10
		i //= 10
	return s

def find_4digs(m, MaxNum, 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))
	return sts

def find_5digs(nums, MaxNum, MaxSum):
	for s in 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)
		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))
	return nums

def max_sumDig(MaxNum, MaxSum):
	nums = find_4digs(1000, MaxNum, MaxSum)
	nums = find_5digs(nums, MaxNum, MaxSum)
	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):
	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]