Grouping numbers and sums python - python

I was given some numbers lets say
1 2 3 4 5 6 7
Would there be some way to find a way to group them so that the sum of the multiple groups is odd then even? I was given this problem for fun.
So far, I have tried something like this,
numbers="7 1 3 5 7 9 11 13"
a_list = numbers.split()
map_object = map(int, a_list)
list_of_integers = list(map_object)
print(list_of_integers)
N=list_of_integers[0]
def subset_sumed(numbers, target, partial=[]):
s = sum(partial)
if s == target:
print("sum(%s)=%s" % (partial, target))
print(partial)
return(s)
if s >= target:
return
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i + 1:]
subset_sumed(remaining, target, partial + [n])
del list_of_integers[0]
list_of_integers.sort()
sumed=list_of_integers[-1]+list_of_integers[-2]
sumss=3
possible_combinations=[]
while sumss<sumed:
a=subset_sumed(list_of_integers,int(sumss))
sumss = int(sumss)+1
possible_combinations.append(a)
i=0
nextint1=2
nextint2=1
groupnumber=0
integersused=[]
print(possible_combinations)

This will get even and then odd groups (groups of alternating parity).
The approach uses recursion and the fact that adding an even number to a number doesn't alter the parity.
Explanation is in the comments below (it is mostly comments).
def get_groups(remaining, curr_sum, group, target, result):
# case 1. End condition / base case
if not remaining:
# If the current group's sum matches target parity, simply append it as its own group
# case 1.a
if curr_sum % 2 == target:
return result + [group]
if result:
# case 1.b
# combine this group with the previous one
result[-1] = result[-1] + group
else:
# case 1.d
# There's no previous group to combine with
print('impossible!')
return None
# case 1.c
# If this group's sum is odd, but the target parity is even (which is true at this point)
# then the previous group's sum was odd and adding the group to previous group makes even
# and an even group can be added to its previous group without changing that group's parity
if curr_sum % 2 == 1:
last = result.pop()
result[-1] = result[-1] + last
return result
# case 2. reached target parity with current group's sum
if curr_sum > 0 and curr_sum % 2 == target:
return get_groups(remaining, 0, [], 1 - target, result + [group])
# case 3. keep moving rightwards, including the leftmost element into current group
head = remaining[0]
return get_groups(remaining[1:], curr_sum + head, group + [head], target, result)
def get_even_odd_groups(a):
return get_groups(a, 0, [], 0, [])
A = [7, 1, 3, 5, 7, 9, 11, 13]
B = [7, 1, 3, 5, 7, 9, 11, 13, 2, 4, 6]
C = [7, 1, 3, 5, 7, 9, 11]
D = [9, 2, 2]
print(get_even_odd_groups(A)) # case 1.a
print(get_even_odd_groups(B)) # case 1.b (but not 1.c)
print(get_even_odd_groups(C)) # case 1.c (and therefore also 1.b)
print(get_even_odd_groups(D)) # case 1.c (impossible!)
Output:
[[7, 1], [3], [5, 7], [9], [11, 13]]
[[7, 1], [3], [5, 7], [9], [2, 11, 13, 2, 4, 6]]
[[7, 1], [3], [5, 7, 9, 11]]
impossible!
None

Related

Swapping opposite elements of a List of Integers if either is Odd

Write a program with the definition of a function named Array_Swap() that will accept an integer list & its size as arguments and the function will swap elements in such a way that the first element is swapped with the last element, the second element is swapped with the second last element and so on, only if anyone or both the elements are odd and display the result.
If initially, a list of seven elements is: [5, 16, 4, 7, 19, 8, 2], the contents of the list after the execution should be:
[2, 16, 19, 7, 4, 8, 5].
def Array_Swap(List,Size):
for i in range (Size//2):
List[i]=List[Size//2-i]
print(List)
L=[]
n=int(input("Enter number of elements"))
for i in range(n):
x=int(input("Enter element"))
L.append(x)
Array_Swap(L,len(L))
The size/length of the list is not relevant because it can be obtained by len(list). And even then it's not required to conditionally swap items in the list. I suggest that the Size parameter be removed, but considering it's an assignment, it can be given a default of None so that it can be ignored by the caller if desired.
The following algorithm zips the input list with its reverse to form pairs relative to their index from the front and end of the list respectively, i.e. the first and last items are paired, the second and second last are paired, etc. Once the items are paired it is simply a matter of iterating over the list and emitting the second number of the pair if either number is odd, or the first number if neither is odd - effectively swapping the pairs as required.
This is done in-place (that's what the List[:] does) with a list comprehension.
def ArraySwap(List, Size=None):
List[:] = [b if (a % 2 or b % 2) else a
for a, b in zip(List, reversed(List))]
print(List)
>>> l = [5, 16, 4, 7, 19, 8, 2]
>>> ArraySwap(l)
[2, 16, 19, 7, 4, 8, 5]
>>> l
[2, 16, 19, 7, 4, 8, 5]
>>> l = list(range(1,30))
>>> ArraySwap(l)
[29, 2, 27, 4, 25, 6, 23, 8, 21, 10, 19, 12, 17, 14, 15, 16, 13, 18, 11, 20, 9, 22, 7, 24, 5, 26, 3, 28, 1]
>>> ArraySwap([1])
[1]
>>> ArraySwap([])
[]
To swap two elements in the list, use the pattern a, b = b, a.
If i is the index of a list item, it's opposite/mirror element is -(i+1), or - i - 1.
so for the 0th element (first one), the mirror is -(0+1), = -1
using that as the indexer for the element, swap the two list elements IF
check that at least one of them is odd before swapping:
def Array_Swap(List,Size):
for i in range (Size // 2):
if List[i] % 2 == 1 or List[-(i+1)] % 2 == 1:
List[i], List[-(i+1)] = List[-(i+1)], List[i]
print(List)
L = [5, 16, 4, 7, 19, 8, 2] # use your input blocks as before, this is an example
Array_Swap(L,len(L))
Output: [2, 16, 19, 7, 4, 8, 5]
(And if L = [5, 16, 4, 7, 19, 8, 1, 2], output is [2, 1, 4, 19, 7, 8, 16, 5].)
Btw, you don't need to pass in the size of the list as a parameter.
You could do just: for i in range(len(List) // 2)
Another solution:
def Array_Swap(List, Size=None):
if Size is None:
Size = len(List)
for (i, j) in zip(range(Size // 2), range(Size - 1, Size // 2, -1)):
if List[i] % 2 or List[j] % 2:
List[i], List[j] = List[j], List[i]
print(List)
Alternatively:
Size parameter is redundant since python's list instance knows its own size
Use bitwise operatos & | >>... possibly cheaper than modulus % and divide / operations.
def Array_Swap(List):
for i in range(len(List) >> 1):
if (List[i] | List[-i-1]) & 1:
List[i], List[-i-1] = List[-i-1], List[i]
print(List)
The standard way to swap two variables in Python is:
a, b = b, a
In this case, you would do:
lst[i], lst[size - i - 1] = lst[size - i - 1], lst[i]
which swaps the ith element with the element that is at index size - i - 1 (i.e. the ith index from the end).
The other issue with your code is that it doesn't check whether either of the elements being swapped are odd, which you can resolve by adding the condition:
if lst[i] % 2 or lst[size - i - 1] % 2:
before doing the swap. This uses the modulo operator (%) to check the parity of the elements. Taking a number modulo 2 will return 1 if the number is odd. If either are odd (1 has a truth value of True), the condition would succeed and the swap will be performed.
Finally, your function was printing the list, rather than returning it. Its usually best to return a result and print the returned result.
The full working version, with the above three changes is as follows:
def list_swap(lst, size):
for i in range(size // 2):
if lst[i] % 2 or lst[size - i - 1] % 2:
lst[i], lst[size - i - 1] = lst[size - i - 1], lst[i]
return lst
l = []
n = int(input("Enter number of elements: "))
for _ in range(n):
x = int(input("Enter element: "))
l.append(x)
result = list_swap(l, len(l))
print(result)
Also note, I've changed all the variables to be lowercase, which is standard in Python.
With your shown example:
Enter number of elements: 7
Enter element: 5
Enter element: 16
Enter element: 4
Enter element: 7
Enter element: 19
Enter element: 8
Enter element: 2
[2, 16, 19, 7, 4, 8, 5]

How to if given a list of integers and a number called x, return recursively the sum of every x'th number in the list

So, How to if given a list of integers and a number called x, return recursively the sum of every x'th number in the list.
In this task "indexing" starts from 1, so if x = 2 and nums = [2, 3, 4, -9], the output should be -6 (3 + -9).
X can also be negative, in that case indexing starts from the end of the list, see examples below.
If x = 0, the sum should be 0 as well.
For example:
print(x_sum_recursion([], 3)) # 0
print(x_sum_recursion([2, 5, 6, 0, 15, 5], 3)) # 11
print(x_sum_recursion([0, 5, 6, -5, -9, 3], 1)) # 0
print(x_sum_recursion([43, 90, 115, 500], -2)) # 158
print(x_sum_recursion([1, 2], -9)) # 0
print(x_sum_recursion([2, 3, 6], 5)) # 0
print(x_sum_recursion([6, 5, 3, 2, 9, 8, 6, 5, 4], 3)) # 15
I have been trying to do this function for 5 hours straight!!!
Would like do see how someone else would solve this.
This is the best i have come up with.
def x_sum_rec_Four(nums: list, x: int) -> int:
if len(nums) == 0:
return 0
elif len(nums) < x:
return 0
elif x > 0:
i = x - 1
return nums[i] + x_sum_rec_Four(nums[i + x:], x)
elif x < 0:
return x_sum_rec_Four(nums[::-1], abs(x))
My problem with this recursion is that the finish return should be:
if len(nums) < x:
return nums[0]
but that would pass things like ([2, 3, 6], 5)) -->> 2 when it should be 0.
If you really need to do it recursively, you could pop x-1 elements from the list before each call, follow the comments below:
def x_sum_recursion(nums, x):
# if x is negative, call the function with positive x and reversed list
if x < 0:
return x_sum_recursion(nums[::-1], abs(x))
# base case for when x is greater than the length of the list
if x > len(nums):
return 0
# otherwise remove the first x-1 items
nums = nums[x-1:]
# sum the first element and remove it from the next call
return nums[0] + x_sum_recursion(nums[1:], x)
print(x_sum_recursion([], 3)) # 0
print(x_sum_recursion([2, 5, 6, 0, 15, 5], 3)) # 11
print(x_sum_recursion([0, 5, 6, -5, -9, 3], 1)) # 0
print(x_sum_recursion([43, 90, 115, 500], -2)) # 158
print(x_sum_recursion([1, 2], -9)) # 0
print(x_sum_recursion([2, 3, 6], 5)) # 0
print(x_sum_recursion([6, 5, 3, 2, 9, 8, 6, 5, 4], 3)) # 15
However, you can do it in a one liner simple and pythonic way:
print(sum(nums[x-1::x] if x > 0 else nums[x::x]))
Explanation:
you slice the list using nums[start:end:increment] when you leave the end empty it slices from the starting position till the end of the list and increments by the increment specified

To obtain a range of particular value form a list

Objective:
To obtain sum of the integers from a list, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
Input Master List
a=[4, 5, 6, 7, 9,2, 6,8,9]
My code so far
z6_ind=[]
z9_ind=[]
z69_ind=[]
x=None
for i,v in enumerate(a):
if v==6:
z6_ind.append(i)
if v==9:
z9_ind.append(i)
print(z6_ind. z9_ind)
My idea is to obtain the indexes of the master list in terms of separate lists (eg. z6_ind, z9_ind and finally the problematic z69_ind which should contain the range in terms of [[2,4],[6,8]] that should be excluded from the master list while sum calculation.
From above script, it gives z9_ind equals to [4, 8] whereas z6_ind equals to [2, 6].
Thanks !
I am not sure if I caught it correctly, but do you want this code?
a = [4, 5, 6, 7, 9, 2, 6, 8, 9]
sigma = 0
exc_ind = []
flag = False
for ind, item in enumerate(a):
if item == 6 and not flag:
flag = True
exc_ind.append([])
exc_ind[-1].append(ind)
elif item == 9 and flag:
exc_ind[-1].append(ind)
flag = False
elif not flag:
sigma += item
print(sigma)
print(exc_ind)
The result:
11
[[2, 4], [6, 8]]
A verbose version with generator:
a=[4, 5, 6, 7, 9,2, 6,8,9]
def iterate(iterable):
stop = False
for i in iterable:
if i == 6:
if stop == False:
stop = True
continue
elif i == 9:
if stop == True:
stop = False
continue
if stop == False:
yield i
print(sum(iterate(a))) # will sum 4, 5 and 2
Prints:
11
If you want to use the part of your code:
a_sum = sum(a)
to_reduce = 0
for (bot,top) in zip(z6_ind, z9_ind):
to_reduce += sum(a[bot:top+1])
Basically zip "pairs" both indexes and get sums between them - numbers you want to reduce a_sum by:
result = a_sum - to_reduce
You can do the following:
import numpy as np
a=np.array([4, 5, 6, 7, 9,2, 6,8,9])
ind1 = np.where(a == 6)[0]
ind2 = np.where(a == 9)[0]
indices = [item for i in zip(ind1, ind2) for item in np.arange(i[0], i[1]+1)]
result = sum(a) - sum(a[indices])
print (result)
Output
11

Summing numbers in a list except those between 6 and 7

I'm attempting to write a function which takes a list and sums all the numbers in the list, except it ignores sections of the list starting with a list and extending to a 7, but continues to sum after the 7. Here is my code:
def sum67(nums):
i = 0
sum = 0
while i < len(nums):
k = 0
if nums[i] != 0:
sum += nums[i]
i += 1
if nums[i] == 6:
for j in range(i + 1, len(nums)):
if nums[j] != 7:
k += 1
if nums[j] == 7:
k += 2
i += k
Test cases show that 6 and proceeding numbers up until and including 7 are ignored while other numbers are added to the sum, and numbers after the 7 are also added to the sum (as was intended), but for some reason any 7 after the first 7 after a 6 is not summed - this is not what I want and I'm not sure why it's happening. Any suggestions?
Test case results:
[1, 2, 2 Expected: 5. My result: 5 (OK)
[1, 2, 2, 6, 99, 99, 7] Expected: 5. My result: 5 (OK)
[1, 1, 6, 7, 2] Expected: 4 My result: 4 (Chill)
[1, 6, 2, 2, 7, 1, 6, 99, 99, 7] Expected: 2 My result: 1 (Not chill)
[1, 6, 2, 6, 2, 7, 1, 6, 99, 99, 7] Expected: 2 My result: 1 (Not chill)
[2, 7, 6, 2, 6, 7, 2, 7] Expected: 18 My result: 9 (Not chill)
`
def sum67(nums):
# flag to know if we are summing
active = True
tot = 0
for n in nums:
# if we hit a 6 -> deactivate summing
if n == 6:
active = False
if active:
tot += n
# if we hit a seven -> reactivate summing
if n == 7 and not active:
active = True
return tot
The posted code is completely broken.
For example for a list without any 6,
i will be out of bounds of the list when reaching the nums[i] == 6 condition on the last element.
You need to completely rethink the conditions inside the loop.
Here's one approach that will work.
If the current number is 6,
then skip until you see a 7, without adding to the sum.
Otherwise add to the sum.
After performing either of these two actions (skipping numbers or adding to the sum),
increment i.
def sum67(nums):
i = 0
total = 0
while i < len(nums):
if nums[i] == 6:
for i in range(i + 1, len(nums)):
if nums[i] == 7:
break
else:
total += nums[i]
i += 1
return total
Here is an intermediate alternative for learning new Python techniques:
import itertools as it
def span_sum(iterable, start=6, end=7):
"""Return the sum of values found between start and end integers."""
iterable = iter(iterable)
flag = [True]
result = []
while flag:
result.extend(list(it.takewhile(lambda x: x!=start, iterable)))
flag = list(it.dropwhile(lambda x: x!=end, iterable))
iterable = iter(flag)
next(iterable, [])
return sum(result)
# Tests
f = span_sum
assert f([1, 2, 2]) == 5
assert f([1, 2, 2, 6, 99, 99, 7] ) == 5
assert f([1, 6, 2, 2, 7, 1, 6, 99, 99, 7]) == 2
assert f([1, 6, 2, 6, 2, 7, 1, 6, 99, 99, 7]) == 2
assert f([2, 7, 6, 2, 6, 7, 2, 7]) == 18
In principle, this function filters the input, collecting values into a result that meet your condition and drops the rest, then the sum is returned. In particular you can observe the following techniques:
extending a list
itertools, e.g. itertools.takewhile, itertools.dropwhile
iterators and generators
next() function and default values
sum() function
assertion testing

How to divide list into 3 sections that are equal in length(sort of) - Python

Ok so like lets say a list of length n. n>= 5
I have to choose two index's in the list that will be the cutting point. These 2 elements will be removed as the list will become 3 new lists.
There will be 3 sections: A , B and C.
A must be bigger or equal to B. and B must be bigger or equal to C. The difference between all 3 sections can only be a maximum of one. With these restrictions what is the formula in finding the 2 index's of a list with the length n?
For Example a list with 5 elements. The 2 index's would be index 1 and index 3.
[1,2,3,4,5] = > [1] [3] [5] with 2 and 4 being the elements that were removed due to the specific index's being cut.
A bigger list with the length of 19 for example
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] The index's that will be the cutting points are index 6 and index 13.
The 3 new formed lists will be [1,2,3,4,5,6] [8,9,10,11,12,13] and [15,16,17,18,19]. You can see that the first two are bigger than the last one as the rules state and the difference in length between each list is not bigger than 1.
def cut(l):
i1 = len(l) / 3
i2 = i1 + (len(l) + 2) / 3
a = l[ : i1]
b = l[i1 + 1 : i2]
c = l[i2 + 1 : ]
return [a, l[i1], b, l[i2], c]
for i in xrange(6, 10):
print cut(list(xrange(1, i)))
# => [[1], 2, [3], 4, [5]]
# [[1, 2], 3, [4], 5, [6]]
# [[1, 2], 3, [4, 5], 6, [7]]
# [[1, 2], 3, [4, 5], 6, [7, 8]]
def split(myList):
div, mod = divmod(len(myList)-2, 3)
indices = [div] * 3
for i in range(mod):
indices[i] += 1
parts = []
for i in range(3):
parts.append( myList[:indices[i]] )
myList = myList[indices[i]+1:]
return parts
print split(range(1,6))
print split(range(1,20))
Output:
[[1], [3], [5]]
[[1, 2, 3, 4, 5, 6], [8, 9, 10, 11, 12, 13], [15, 16, 17, 18, 19]]
A generalization to more than 3 pieces:
def findCutPoints(n,k):
q,r = divmod(n-k+1,k)
bigSteps = list(range(q+2,r*(q+2) + 1, q+2))
littleSteps = list(range(r*(q+2) + (q+1),n,q + 1))
return bigSteps + littleSteps
Output:
>>> findCutPoints(19,3)
[7, 14]
>>> findCutPoints(34,4)
[9, 18, 27]
Note that this function returns the actual numbers from the range [1,...,n] which are removed. The 0-based indices of those numbers are 1 less and the function can be easily modified to give the indices rather than the elements. For completeness sake, here is the modified version which returns the indices (e.g. [6,13] rather than [7,14]):
def findCutPoints(n,k):
q,r = divmod(n-k+1,k)
bigSteps = list(range(q+1, r*(q+2), q+2))
littleSteps = list(range(r*(q+2) + q, n, q + 1))
return bigSteps + littleSteps

Categories