Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am a beginner so if this question sounds stupid/unclear or very easy , please bear with me.
How can I add a list of numbers together in order to reach a target number or get as close as possible? For example, here is a list of numbers: (2,3,4,7,20,25), goal = 105. The result should be this: (25,25,25,25,3,2). The order of given numbers matters; always start with the biggest number in the list and add them up in order get close to the given value, so it will choose the next digit to test. the result could be also (20, 20, 20, 20, 25), which is not right in this case, because it doesn't follow the order of numbers. The algorithm only jump for the next number if it can feet otherwise can't jump.
Best M
l=(2,3,4,7,20,25)
goal = 105
a=max(l)
b=0
res=[]
while b<=goal-24:
b+=a
t=goal-b
res.append(a)
g=0
for x in l:
g+=x
if g==t:
res.append(x)
res.append(g-x)
break
print (res)
Output:
>>>
[25, 25, 25, 25, 3, 2]
>>>
I found this solution, however, really annoyed me :-)! Tricky part is while b<=goal-24: , other codes are basic Python.
I would take a dynamic-programming approach:
def fewest_items_closest_sum_with_repetition(items, goal):
"""
Given an array of items
where each item is 0 < item <= goal
and each item can be used 0 to many times
Find the highest achievable sum <= goal
Return any shortest (fewest items) sequence
which adds to that sum.
"""
assert goal >= 0, "Invalid goal"
# remove any duplicate or invalid items
items = set(item for item in items if 0 < item <= goal)
# sort descending (work with largest values first)
items = sorted(items, reverse=True)
# start with the no-item sequence
best = {0: []}
active = {0: []}
# while we have further seeds to work from
while active:
nactive = {}
for item in items:
for total, seq in active.items():
# find next achievable sum
ntotal = total + item
# if it is a valid subgoal and has not already been found
if (ntotal <= goal and ntotal not in best):
# save it
best[ntotal] = nactive[ntotal] = [item] + seq
if ntotal == goal:
# best possible solution has been found!
break
active = nactive
# return the best solution found
return best[max(best)]
which then runs like
>>> fewest_items_closest_sum_with_repetition([2,3,4,7,20,25], 105)
[25, 20, 20, 20, 20]
>>> fewest_items_closest_sum_with_repetition((40,79), 80)
[40, 40]
Is this right? I don't have time to test right now.
def solution(numbers, goal):
curr = 0
numbers = sorted(numbers)
while curr < goal:
if not numbers: break
n = numbers.pop()
while n + curr <= goal:
yield n
curr += n
list(solution([2,3,4,7,20,25], 105))
Results:
[25, 25, 25, 25, 4]
If speed is not an issue, here's an ultimately correct response:
import itertools
def change_maker(coins, amount):
for r in range(amount//max(coins), amount//min(coins)+1):
possibilities = (combo for combo in itertools.combinations_with_replacement(coins, r) if sum(combo) == amount)
try:
result = next(possibilities)
except StopIteration:
# no solution with current r
continue
else:
return result
This will always return the optimum result, but in some cases can calculate an ABSURD number of combinations to get there.
DEMO:
>>> coins = (2, 3, 4, 7, 20, 25)
>>> goals = 105
>>> print(change_maker(coins, goal))
[20, 20, 20, 20, 25]
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
my_list = [['Chris',33,'JAN'],['Katia',40,'JAN'],['Petunia',54,'JAN'],['Clee',26,'JAN'],['katt',73,'JAN'],['battt',83,'JAN'],['FRIES',59,'FEB'],['GGEEZ',89,'FEB'],['SHEEESH',25,'MAR']]
threshold = [[217, 'JAN'], [104, 'FEB'], [18, 'MAR']]
output: [['Chris','Katia','Petunia','Clee','katt'],['FRIES','GGEEZ'],['SHEEESH']]
I want to make a new list with the first element in the nested array (the names) until the sum of the second elements in the nested array passes the 217 for JAN, 104 for FEB and 18 for MARCH.
I dont know how to do it since both of the lists are are indented and I find that hard to work with, But it should check it in a loop if my_list[2] == threshold[1] and sum the my_list[1]s until it is greater or equal to threshold[0] than it should go and check if the and check if my_list[2] == threshold[1] (but this time we skip the remaining januaries and check if the february is equal to the mylist and so on, its hard to articulate
Try:
my_list = [['Chris',33,'JAN'],['Katia',40,'JAN'],['Petunia',54,'JAN'],['Clee',26,'JAN'],['katt',73,'JAN'],['battt',83,'JAN'],['FRIES',59,'FEB'],['GGEEZ',89,'FEB'],['SHEEESH',25,'MAR']]
threshold = [[217, 'JAN'], [104, 'FEB'], [18, 'MAR']]
results = []
for max_num, month in threshold:
accumulator = []
count = 0
for s, num, month_ in my_list:
if month == month_ and count < max_num:
accumulator.append(s)
results.append(accumulator)
print(results)
output:
[['Chris', 'Katia', 'Petunia', 'Clee', 'katt', 'battt'], ['FRIES', 'GGEEZ'], ['SHEEESH']]
output = []
for a,b in threshold:
sum = 0
curr = []
for x,y,z in my_list:
if z == b and sum < a:
sum += y
curr.append(x)
output.append(curr)
write a python code to find out max and second max number from a list using only one loop
Python program to find second largest
number in a list
list of numbers - length of list should be at least 2
list1 = [10, 20, 4, 45, 99]
max=max(list1[0],list1[1])
secondmax=min(list1[0],list1[1])
for i in range(2,len(list1)):
if list1[i]>max:
secondmax=max
max=list1[i]
else:
if list1[i]>secondmax:
secondmax=list1[i]
print("Second highest number is : ",str(secondmax))
one loop without sort or extra data structures:
def find_two_max(lst : list):
if len(lst) < 2:
raise Exception ("List size must be >= 2")
max1=max2=float('-inf')
for number in lst:
if number >= max1:
max2=max1
max1=number
elif number > max2:
max2=number
return max1, max2
l=[99, 299, 0, 2,3,4,5,1000]
print("The highest two numbers are %s , %s " % find_two_max(l))```
You can also do it without a for loop by calling max() on the list twice - and removing the result of the first call:
list1 = [10, 20, 4, 45, 99]
list1.remove(max(list1))
print(max(list1))
But this is going to be slower than simply using a for loop as you have in your approach, simply because it has to traverse the list twice.
If i understood your answer you can try this code(also negative number):
list1 = [99, 20, 4, 10, 45]
if len(list1) < 2:
raise Exception ("List size must be >= 2")
first_max=list1[0]
second_max=list1[-1]
#I used the position to avoid the same number(index) for the first and second max
position_first_max=0
position_second_max=len(list1)-1
for idx,item in enumerate(list1):
if item>first_max:
second_max=first_max
position_second_max=position_first_max
first_max=item
position_first_max=idx
else:
if item>second_max and position_first_max!=idx:
second_max=item
position_second_max=idx
print("First highest number is : ",str(first_max))
print("Second highest number is : ",str(second_max))
i tested with different numbers in different position and works.
Hope this helps.
One simple solution is to use built-in Python functions to sort() the list. After sorting the list, you can pull out the second to last item by using the index:
list1 = [10, 20, 4, 45, 99]
list1.sort()
print( 'Highest number is : ', list1[-1] )
print( 'Second highest number is : ', list1[-2] )
I have a list likes
lst = [20, 40, 110]
I want to find the highest power of 2 in the list satisfied as
For the first number, the highest power of 2 will get the first element of the list as input. So the result is 16 (closest to 20)
For the next numbers, it will get the summation of previous result (i.e 16) and current number (.i.e 40) so the closest number will be 32 (closest 40 +16)
So the output what I expect is
lst_pow2 = [16, 32, 128]
This is my current code to find the highest number of a number, but for my problem it should change something because my input is list. Any suggestion? Thanks
# Python3 program to find highest
# power of 2 smaller than or
# equal to n.
import math
def highestPowerof2(n):
p = int(math.log(n, 2));
return int(pow(2, p));
So what I tried but it does not do the summation
lst_power2 = [highestPowerof2(lst[i]) for i in range(len(lst))]
You can perhaps use the following :
lst_power2 = [highestPowerof2(lst[i]+((i>0) and highestPowerof2(lst[i-1]))) for i in range(len(lst))]
instead of
lst_power2 = [highestPowerof2(lst[i]) for i in range(len(lst))]
You may want to modify your approach thus:
Modify your function to take 2 integers. prev_power and curr_num (this was n in your code)
Calculate the power of 2 for the first number and add to a result list
Now pass this number and the next number in the list to your highestPowerof2 function
Use an extra variable that keeps track of the value to be added, and build your logic while iterating.
lst = [20, 40, 110]
import math
def highestPowerof2(n):
p = int(math.log(n, 2)) #you do not need semi colons in python
return int(pow(2, p))
acc = 0 #to keep track of what was the last highest* power
result = []
for n in lst:
result.append(highestPowerof2(n + acc))
acc = result[-1]
print(result)
#Output:
[16, 32, 128]
This question has an accepted answer but I thought this would be a good problem that could also be solved by using a generator. The accepted answer is definitely compact but I though it would be fun to give this solution as well.
lst = [20, 40, 110]
import math
def highestPowerof2(lst):
last = 0
for element in lst:
p = int(math.log(element + last, 2))
last = int(pow(2, p)) # Remember the last value
yield last
lst_power2 = [i for i in highestPowerof2(lst)]
print(lst_power2)
You could use reduce() too:
functools.reduce(lambda res,n:res+[highestPowerof2(n+res[-1])],lst,[0])[1:]
which is short, just the [1:] is ugly at the end
Or as:
functools.reduce(lambda res,n:res+[highestPowerof2(n+(len(res) and res[-1]))],lst,[])
which does not need the slicing, but it is less readable inside.
Full example:
import math,functools
def highestPowerof2(n):
p = int(math.log(n, 2))
return int(pow(2, p))
lst = [20, 40, 110]
print(functools.reduce(lambda res,n:res+[highestPowerof2(n+res[-1])],lst,[0])[1:])
print(functools.reduce(lambda res,n:res+[highestPowerof2(n+(len(res) and res[-1]))],lst,[]))
The following python code is to traverse a 2D grid of (c, g) in some special order, which is stored in "jobs" and "job_queue". But I am not sure which kind of order it is after trying to understand the code. Is someone able to tell about the order and give some explanation for the purpose of each function? Thanks and regards!
import Queue
c_begin, c_end, c_step = -5, 15, 2
g_begin, g_end, g_step = 3, -15, -2
def range_f(begin,end,step):
# like range, but works on non-integer too
seq = []
while True:
if step > 0 and begin > end: break
if step < 0 and begin < end: break
seq.append(begin)
begin = begin + step
return seq
def permute_sequence(seq):
n = len(seq)
if n <= 1: return seq
mid = int(n/2)
left = permute_sequence(seq[:mid])
right = permute_sequence(seq[mid+1:])
ret = [seq[mid]]
while left or right:
if left: ret.append(left.pop(0))
if right: ret.append(right.pop(0))
return ret
def calculate_jobs():
c_seq = permute_sequence(range_f(c_begin,c_end,c_step))
g_seq = permute_sequence(range_f(g_begin,g_end,g_step))
nr_c = float(len(c_seq))
nr_g = float(len(g_seq))
i = 0
j = 0
jobs = []
while i < nr_c or j < nr_g:
if i/nr_c < j/nr_g:
# increase C resolution
line = []
for k in range(0,j):
line.append((c_seq[i],g_seq[k]))
i = i + 1
jobs.append(line)
else:
# increase g resolution
line = []
for k in range(0,i):
line.append((c_seq[k],g_seq[j]))
j = j + 1
jobs.append(line)
return jobs
def main():
jobs = calculate_jobs()
job_queue = Queue.Queue(0)
for line in jobs:
for (c,g) in line:
job_queue.put((c,g))
main()
EDIT:
There is a value for each (c,g). The code actually is to search in the 2D grid of (c,g) to find a grid point where the value is the smallest. I guess the code is using some kind of heuristic search algorithm? The original code is here http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/gridsvr/gridregression.py, which is a script to search for svm algorithm the best values for two parameters c and g with minimum validation error.
permute_sequence reorders a list of values so that the middle value is first, then the midpoint of each half, then the midpoints of the four remaining quarters, and so on. So permute_sequence(range(1000)) starts out like this:
[500, 250, 750, 125, 625, 375, ...]
calculate_jobs alternately fills in rows and columns using the sequences of 1D coordinates provided by permute_sequence.
If you're going to search the entire 2D space eventually anyway, this does not help you finish sooner. You might as well just scan all the points in order. But I think the idea was to find a decent approximation of the minimum as early as possible in the search. I suspect you could do about as well by shuffling the list randomly.
xkcd readers will note that the urinal protocol would give only slightly different (and probably better) results:
[0, 1000, 500, 250, 750, 125, 625, 375, ...]
Here is an example of permute_sequence in action:
print permute_sequence(range(8))
# prints [4, 2, 6, 1, 5, 3, 7, 0]
print permute_sequence(range(12))
# prints [6, 3, 9, 1, 8, 5, 11, 0, 7, 4, 10, 2]
I'm not sure why it uses this order, because in main, it appears that all candidate pairs of (c,g) are still evaluated, I think.
I have a number of nodes in a network. The nodes send status information every hour to indicate that they are alive. So i have a list of Nodes and the time when they were last alive. I want to graph the number of alive nodes over the time.
The list of nodes is sorted by the time they were last alive but i cant figure out a nice way to count how many are alive at a each date.
from datetime import datetime, timedelta
seen = [ n.last_seen for n in c.nodes ] # a list of datetimes
seen.sort()
start = seen[0]
end = seen[-1]
diff = end - start
num_points = 100
step = diff / num_points
num = len( c.nodes )
dates = [ start + i * step for i in range( num_points ) ]
What i want is basically
alive = [ len([ s for s in seen if s > date]) for date in dates ]
but thats not really efficient. The solution should use the fact that the seen list is sorted and not loop over the whole list for every date.
this generator traverses the list only once:
def get_alive(seen, dates):
c = len(seen)
for date in dates:
for s in seen[-c:]:
if s >= date: # replaced your > for >= as it seems to make more sense
yield c
break
else:
c -= 1
The python bisect module will find the correct index for you, and you can deduct the number of items before and after.
If I'm understanding right, that would be O(dates) * O(log(seen))
Edit 1
It should be possible to do in one pass, just like SilentGhost demonstrates. However,itertools.groupby works fine with sorted data, it should be able to do something here, perhaps like this (this is more than O(n) but could be improved):
import itertools
# numbers are easier to make up now
seen = [-1, 10, 12, 15, 20, 75]
dates = [5, 15, 25, 50, 100]
def finddate(s, dates):
"""Find the first date in #dates larger than s"""
for date in dates:
if s < date:
break
return date
for date, group in itertools.groupby(seen, key=lambda s: finddate(s, dates)):
print date, list(group)
I took SilentGhosts generator solution a bit further using explicit iterators. This is the linear time solution i was thinking of.
def splitter( items, breaks ):
""" assuming `items` and `breaks` are sorted """
c = len( items )
items = iter(items)
item = items.next()
breaks = iter(breaks)
breaker = breaks.next()
while True:
if breaker > item:
for it in items:
c -= 1
if it >= breaker:
item = it
yield c
break
else:# no item left that is > the current breaker
yield 0 # 0 items left for the current breaker
# and 0 items left for all other breaks, since they are > the current
for _ in breaks:
yield 0
break # and done
else:
yield c
for br in breaks:
if br > item:
breaker = br
break
yield c
else:
# there is no break > any item in the list
break