Unique sums greater than a number - python

So I'm trying to write a code that takes a list of numbers between 1 and 10 and finds sums that are greater or equal than 10 and then remove those numbers from the list. Here's the twist: first you need to check if there is any 10 in the list, the any couple of numbers that sum to 10, then any 3 numbers and so on until 5. Also, the lower the numbers summed the better. So you need to get rid of most numbers when summing couples. So far I managed to do the couples:
n = input("How many numbers in the list? \n")
throw = []
for i in range(int(n)):
throw.append(random.randint(1, 10))
throw.sort()
increments = 0
print(throw)
increments += throw.count(10)
throw = list(filter(lambda i: i != 10, throw))
high = len(throw)-1
low = 0
acceptable_couples = []
get_rid = []
while low < high:
sums = throw[high] + throw[low]
if sums >= 10:
increments += 1
get_rid.append(throw[high])
get_rid.append(throw[low])
acceptable_couples.append((throw[high], throw[low]))
high -= 1
low += 1
else:
low += 1
for i in get_rid:
throw.remove(i)
I also did the pairs of 3 and was thinking to apply the same method for 4, and 5:
while len(throw) >= 3:
z = 0
x = list(itertools.combinations(throw, 3))
for couple in x:
if sum(couple) >= 10:
z += 1
i = list(couple)
increments += 1
for j in couple:
throw.remove(j)
break
else:
continue
if z == 0:
break
I was hoping to find a less messy way to do it. This works, but for large number of numbers it seems a lot of useless computation.
Any ideas?

In that case perhaps this would be a solution. In pseudo code:
Read list of numbers and sort from high to low
remove all numbers 10 from the list and add these as a solution
Loop until list is empty
take the largest number in the list (which is the first number as list is sorted) and remove it from the list
Check if by adding the smallest number we can get a sum greater or equal to 10 if not go to a bigger number until we complete the loop. Break loop if a solution is found, add to solutions and remove the element from the list that solved it.
if solved break and repeat the outer while loop with next biggest number in the list. If not solved then add the next biggest number to the sum and remove it from the list and check if we can find a solution adding smaller numbers running the for loop again
Code
import random
n = int(input("How many numbers in the list? \n"))
throw = [random.randint(1, 6) for _ in range(n)]
print(throw)
throw.sort(reverse=True)
print(throw)
list_of_solved_sets = []
# remove all numbers 10 from the list and add a solution
while throw and throw[0] == 10:
list_of_solved_sets.append([throw[0]])
del throw[0]
while throw:
# take the largest number in the set (which is the first number
# as list is sorted) and remove it from the list
solved_set = [throw[0]]
_sum = throw[0]
del throw[0]
while throw:
solved = False
# Check if by adding the smallest number we can get
# a sum greater or equal to 10 if not go to a bigger number
# until we complete the loop. Break loop if a solution is found, add
# to solutions and remove element from the list that solved it
for j in range(len(throw) - 1, -1, -1):
if _sum + throw[j] >= 10:
solved_set.append(throw[j])
del throw[j]
list_of_solved_sets.append(solved_set)
solved = True
break
# if solved break and repeat the outer while loop with next biggest number
# in the list. If not solved then add the next biggest number to the sum and
# check if we can find a solution adding smaller numbers running the for
#loop again
if solved:
break
else:
_sum += throw[0]
solved_set.append(throw[0])
del throw[0]
print('List of solved sets:')
for i, solved_set in enumerate(list_of_solved_sets):
print(f' {i+1}: {solved_set}')
Result example:
How many numbers in the list?
10
[3, 2, 5, 1, 6, 3, 4, 3, 2, 1]
[6, 5, 4, 3, 3, 3, 2, 2, 1, 1]
List of solved sets:
1: [6, 4]
2: [5, 3, 2]
3: [3, 3, 2, 1, 1]

Not sure if I understand your question correctly. My interpretation is that you have a set of numbers between 1 and 10 and you need to find the longest sub sets of numbers from this set that sum up to 10 or greater and then remove these numbers from the original set until you can not find any more sets with more than one number.
If this is the correct interpretation than the following should work:
import random
n = int(input("How many numbers in the list? \n"))
throw = [random.randint(1, 10) for _ in range(n)]
print(throw)
throw.sort()
list_of_solved_sets = []
sets_found = True
while sets_found:
_sum = 0
solved_set = []
solved_indexes = []
for index, element in enumerate(throw):
_sum += element
solved_set.append(element)
solved_indexes.append(index)
if _sum >= 10:
break
if len(solved_set) <= 1:
sets_found = False
else:
list_of_solved_sets.append(solved_set)
for index in reversed(solved_indexes):
del throw[index]
print('List of solved sets:')
for i, solved_set in enumerate(list_of_solved_sets):
print(f' {i+1}: {solved_set}')
Note you need to remove the indexes from the list throw in reversed order!

Related

Find position of duplicate elements in list

Basically I want to find and print the positions of all the duplicate elements. Here is my code:
numbers = [7,1,3,6,4,2,5,9,8,10]
n = int(input("Enter a number from 1 to 10 to search for the number's position: "))
def findNum():
count = 0
while numbers[count] != n:
count += 1
numPos = count + 1
print(numPos)
if n in numbers:
print("Calculating position... (takes 9 years so wait)")
findNum()
else:
print("Number not found, next time enter a number from 1 to 10!")
For example I add an extra 7 to numbers:
numbers = [7,1,3,6,4,2,5,9,8,10,7]
Then I want to return the 1st 7's position and also the other 7's position. How to do it?
To get all duplicates use a dictionary with the keys as the numbers in the list and the values the positions, to get the positions use enumerate:
from collections import defaultdict
numbers = [7, 1, 3, 6, 4, 2, 5, 9, 8, 10, 7]
duplicates = defaultdict(list)
# iterate over positions and numbers simultaneously
for i, number in enumerate(numbers):
# accumulate positions to the same number
duplicates[number].append(i)
result = {key: value for key, value in duplicates.items() if len(value) > 1}
print(result)
Output
{7: [0, 10]}
As you can see from the output it returns that 7 appears in position 0 an 10. The overall complexity of this approach is O(n).
The loop:
# iterate over positions and numbers simultaneously
for i, number in enumerate(numbers):
# accumulate positions to the same number
duplicates[number].append(i)
group the different positions (i in the code) by the same number. Using a defaultdict.
The expression:
result = {key: value for key, value in duplicates.items() if len(value) > 1}
is a dictionary comprehension, see some more info here.
numbers = [7,1,7,6,4,2,5,9,8,10,7]
m=[]
for i in range(len(numbers)):
for j in range(i+1,len(numbers),1):
if(numbers[i]==numbers[j]):
m.append(i)
m.append(j)
l=list(set(m))
for i in range(len(l)):
print("First Occurence at position:{}".format(l[i]))

Comparing elements in a list in order using loop or stack/queue

I have a list ls with integer elements between 0 and 100. I want to build a function that counts a number of elements until it encounters an element that has a larger value, and appends the count to the solution list.
In other words, if ls = [5, 10, 1, 1, 20, 1], the solution should be [1, 3, 2]:
1 comes from the first element, 5
3 comes from the second to fourth elements, 10, 1, 1
2 comes from the last two elements, 20, 1
(If ls = [7, 3, 9], the return should be [2,1].)
I used a for loop to perform the task:
def compare_and_count(ls):
answer = []
num = 1
ref = 0
for j in range(1, len(ls)):
try:
if ls[ref + j] <= ls[ref]:
num += 1
else:
answer.append(num)
num = 1
ref = ref + j
except IndexError:
break
answer.append(num)
return answer
I tried to do a value comparison with two movable references, but this raises IndexError and also sometimes neglects the final counting and hence returns an incorrect list. (I added try...except to be free of the IndexError, but the latter problem is still unsolved)
I assume either loop or stack/queue is the most concise way to solve this, but I couldn't land an optimal way yet. Any insight is appreciated.
Edited the answer to correct it .
def my(a):
count = 1
maxval = a[0]
answer = []
for i in range(1, len(a)):
if a[i] > maxval:
maxval = a[i]
answer.append(count)
count = 1
else:
count += 1
answer.append(count)
return answer
I tried to do a value comparison with two movable references
You dont need to, just one moving index i and one count counter with a maxval to check the condition.

Is there a way to add and subtract numbers from a list sequentially?

I'm trying to add and subtract each number in a list like this 1 - 1/3 + 1/5 - 1/7 + 1/9. If you keep on doing this and then multiply the answer by 4 you get an aproximation of pi.
I have a list of odd numbers called ODD but im having trouble adding and subtracing as shown above
I literally just started coding in python today so this could be a simple mistake but I can't find anything online about it
Thanks,
Adam
import time
start_time = time.time()
EVEN = []
ODD = []
y = int(1.e2)
x = range(y)
#-----------------------------------------------------------------------------------------
for i in x:
if i%2 == 0:
print(i)
EVEN.append(i)
else:
print(i)
ODD.append(i)
oc = len(ODD)
ec = len(EVEN)
print("")
print(str(oc) + " " + "Odds Found!")
print(str(ec) + " " + "Evens Found!")
print("--- %s seconds to compute ---" % "{:.2f}".format(((time.time() - start_time))))
time.sleep(3) #START OF PROBLEM
for i in ODD:
fract = 1/ODD[i]-1/ODD[i+1]
sfract = fract + 1/ODD[i+2]
print(fract)
print(sfract)
Your problem is because this loop
for i in ODD:
iterates over elements in a list (for each loop). This is why ODD[i] would result in an index error or would calculate something else than what you're interested in. You should just use the variable i.
flag = True
for i in ODD:
if flag:
fract += 1 / i
else:
fract -= 1/ i
flag = not flag
Besides, since you write in Python I'd recommend using list comprehension:
EVEN = [i for i in x if i % 2 == 0]
ODD = [i for i in x if i % 2 == 1]
There is absolutely no need to use any lists in this program.
arbitrary_number = 1000
sign = 1
total = 0
for n in range(1, arbitrary_number, 2):
total += sign * 1.0 / n
sign = -sign
print(4*total)
I wrote this out with the intention of having each step be clear. There are easier ways to write this with less code. Remember that Python is made to be simple. There is usually one clear way to come up with a solution, but always try experimenting.
number = 0 #initialize a number. This number will be your approximation so set it to zero.
count = 0 #set a count to check for even or odd [from the formula] (-1)^n
for num in range(1,100,2): #skip even values.
"""
The way range works in this case is that you start with 1, end at 100 or an arbitrary
number of your choice and you add two every time you increment.
For each number in this range, do stuff.
"""
if count%2 == 0: #if the count is even add the value
number += 1/num #example add 1, 1/5, 1/9... from number
count += 1 #in order to increment count
else: #when count is odd subtract
number -= 1/num #example subtract 1/3, 1/7, 1/11... from number
count += 1 #increment count by one
number = number*4 #multiply by 4 to get your approximation.
Hope this helps and welcome to Python!
Let's examine the for loop:
for i in ODD:
fract = 1/ODD[i]-1/ODD[i+1]
sfract = fract + 1/ODD[i+2]
print(fract)
print(sfract)
since you declare fract & sfract inside the loop, they do not compute the sum, but only two and three terms of the sum, respectively. If you initialize the variables outside of the loop, their scope will allow them to accumulate the values.
For what you are doing, I would use numpy.float for those variables to prevent overflow.
If you need to add and subtract sequentially in a list, you can use the Python slice operation to create 2 lists with odd and even indexes.
# Example list
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# [1, 3, 5, 7, 9]
add_list = lst[0::2]
# [2, 4, 6, 8]
subtract_list = lst[1::2]
# Now you can add all the even positions and subtract all the odd
answer = sum(add_list) - sum(subtract_list) # Same as 1-2+3-4+5-6+7-8+9

Google Foobar Question - Please Pass The Coded Message

Google Foobar Question:
Please Pass the Coded Messages
You need to pass a message to the bunny prisoners, but to avoid detection, the code you agreed to use is... obscure, to say the least. The bunnies are given food on standard-issue prison plates that are stamped with the numbers 0-9 for easier sorting, and you need to combine sets of plates to create the numbers in the code. The signal that a number is part of the code is that it is divisible by 3. You can do smaller numbers like 15 and 45 easily, but bigger numbers like 144 and 414 are a little trickier. Write a program to help yourself quickly create large numbers for use in the code, given a limited number of plates to work with.
You have L, a list containing some digits (0 to 9). Write a function answer(L) which finds the largest number that can be made from some or all of these digits and is divisible by 3. If it is not possible to make such a number, return 0 as the answer. L will contain anywhere from 1 to 9 digits. The same digit may appear multiple times in the list, but each element in the list may only be used once.
Languages
To provide a Python solution, edit solution.py
To provide a Java solution, edit solution.java
Test cases
Inputs:
(int list) l = [3, 1, 4, 1]
Output:
(int) 4311
Inputs:
(int list) l = [3, 1, 4, 1, 5, 9]
Output:
(int) 94311
Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.
So that's the question, my python code only passes 3 out of 5 tests cases. I spent a few hours but can't find out what cases I am missing. Here is my code:
maximum = [0, 0, 0, 0, 0,0,0,0,0]
def subset_sum(numbers, target, partial=[]):
global maximum
s = sum(partial)
if s%3 == 0:
if s != 0:
str1 = ''.join(str(e) for e in partial)
y = int(str1)
str1 = ''.join(str(e) for e in maximum)
z = int(str1)
if y>z:
maximum = partial
# print maximum
if s >= target:
return # if we reach the number why bother to continue
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i+1:]
subset_sum(remaining, target, partial + [n])
def answer(l):
global maximum
#maximum = [0, 0, 0, 0, 0]
subset_sum(l,sum(l))
maximum = sorted(maximum, key=int, reverse=True)
str1 = ''.join(str(e) for e in maximum)
y = int(str1)
return y
print(answer([3,1,4,1,5,9]))
So what test cases am I not accounting for, and how could I improve it?
try this using combination it may help:
from itertools import combinations
def answer(nums):
nums.sort(reverse = True)
for i in reversed(range(1, len(nums) + 1)):
for tup in combinations(nums, i):
if sum(tup) % 3 == 0: return int(''.join(map(str, tup)))
return 0
Presently, you are forming a number by using adjacent digits only while the question does not say so.
A quick fix would be to set remaining list properly -
remaining = numbers[:i] + numbers[i+1:]
But you need to think of better algorithm.
Update
inputNumbers = [2, 1, 1, 1, 7, 8, 5, 7, 9, 3]
inputNumSorted = sorted(inputNumbers)
sumMax = sum(inputNumbers)
queue = [(sumMax, inputNumSorted)]
found = False
while (len(queue) > 0):
(sumCurrent, digitList) = queue.pop()
remainder = sumCurrent%3
if (remainder == 0):
found = True
break
else :
for index, aNum in enumerate(digitList):
if(aNum%3 == remainder):
sumCurrent -= remainder
digitList.remove(aNum)
found = True
break
else:
newList = digitList[:index]+digitList[index+1:]
if (len(newList) > 0):
queue.insert(0, (sumCurrent-aNum, newList))
if(found):
break
maxNum = 0
if (found):
for x,y in enumerate(digitList):
maxNum += (10**x)*y
print(maxNum)
I believe the solution looks something like this:
Arrange the input digits into a single number, in order from largest to smallest. (The specific digit order won't affect its divisibility by 3.)
If this number is divisible by 3, you're done.
Otherwise, try removing the smallest digit. If this results in a number that is divisible by 3, you're done. Otherwise start over with the original number and try removing the second-smallest digit. Repeat.
Otherwise, try removing digits two at a time, starting with the two smallest. If any of these result in a number that is divisible by 3, you're done.
Otherwise, try removing three digits...
Four digits...
Etc.
If nothing worked, return zero.
Here's the actual solution and this passes in all the test cases
import itertools
def solution(l):
l.sort(reverse = True)
for i in reversed(range(1, len(l) + 1)):
for j in itertools.combinations(l, i):
if sum(tup) % 3 == 0: return int(''.join(map(str, j)))
return 0
Here is a commented solution (that passed all test cases):
def solution(l):
# sort in decending order
l = sorted(l, reverse = True)
# if the number is already divisible by three
if sum(l) % 3 == 0:
# return the number
return int("".join(str(n) for n in l))
possibilities = [0]
# try every combination of removing a single digit
for i in range(len(l)):
# copy list of digits
_temp = l[:]
# remove a digit
del _temp[len(_temp) - i - 1]
# check if it is divisible by three
if sum(_temp) % 3 == 0:
# if so, this is our solution (the digits are removed in order)
return int("".join(str(n) for n in _temp))
# try every combination of removing a second digit
for j in range(1, len(_temp)):
# copy list of digits again
_temp2 = _temp[:]
# remove another digit
del _temp2[len(_temp2) - j - 1]
# check if this combination is divisible by three
if sum(_temp2) % 3 == 0:
# if so, append it to the list of possibilities
possibilities.append(int("".join(str(n) for n in _temp2)))
# return the largest solution
return max(possibilities)
I tried a lot but test case 3 fails .Sorry for bad variable names
import itertools
def solution(l):
a=[]
k=''
aa=0
b=[]
for i in range(len(l)+1):
for j in itertools.combinations(l,i):
a.append(j)
for i in a:
if sum(i)>=aa and sum(i)%3==0 and len(b)<len(i):
aa=sum(i)
b=i[::-1]
else:
pass
b=sorted(b)[::-1]
for i in b:
k+=str(i)
if list(k)==[]:
return 0
else:
return k

Selection Sort (low to high) python

I am trying to write a selection sort algorithm for sorting lists of numbers from lowest to highest.
def sortlh(numList):
if type(numList) != list:
print("Input must be a list of numbers.")
else:
inf = float("inf")
sortList = [0]*len(numList)
count = 0
while count < len(numList):
index = 0
indexLowest = 0
lowest = numList[index]
while index < (len(numList) - 1):
if numList[index + 1] < numList[index]:
lowest = numList[index + 1]
indexLowest = index + 1
index = index + 1
else:
index = index + 1
sortList[count] = lowest
numList[indexLowest] = inf
count = count + 1
return sortList
When I run this code on:
sortlh([9,8,7,6,5,4,3,2,1])
I get (as expected):
[1, 2, 3, 4, 5, 6, 7, 8, 9]
However, when I try another example, I get:
sortlh([1,3,2,4,5,7,6,9,8])
[8, 6, 9, 2, 4, 5, 7, 1, 3]
Does anyone see what is going on here?
Here is how I would suggest rewriting your program.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
i = 0
while i < len(lst):
j = i + 1
i_lowest = i
lowest = lst[i_lowest]
while j < len(lst):
if lst[j] < lowest:
i_lowest = j
lowest = lst[i_lowest]
j += 1
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
i += 1
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)
We don't test the type of the input. Anything that acts like a list will work, and even an iterator will work.
We don't "mutate" the original input list. We only work on a copy of the data.
When we find the lowest number, we swap it with the first number, and then only look at the remaining numbers. Thus we have less work to do on each loop as we have fewer and fewer unsorted numbers.
EDIT:
If you are a beginner, this part might seem too tricky. If it confuses you or you don't like it, just ignore it for now.
This is a more-advanced way to solve this problem in Python. The inner loop simply finds the lowest number and the index of the lowest number. We can use the Python built-in function min() to do this!
We build a "generator expression" that loops over the list, yielding up tuples. Each tuple is the number and its position. Since we want lower numbers to sort lower, we put the number first in the tuple so that min() can properly compare the tuples. Then min() will find the lowest tuple and we get the value and index.
Also, the outer loop is now a for loop with enumerate rather than a while loop using indexing.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
for i, x in enumerate(lst):
lowest, i_lowest = min((n, j) for j, n in enumerate(lst) if j >= i)
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)

Categories

Resources