Related
So essentially it is a simple two sum problem but there are multiple solutions. At the end I would like to return all pairs that sum up to the target within a given list and then tally the total number of pairs at the end and return that as well. Currently can only seem to return 1 pair of numbers.
So far my solution has to been to try and implement a function that counts the amount of additions done, and while that number is less than the total length of the list the code would continue to iterate. This did not prove effective as it would still not take into account other solutions. Any help would be greatly appreciated
I took your code and did a couple of tweaks to where summations were being tested and how the data was being stored. Following is your tweaked code.
def suminlist(mylist,target):
sumlist = []
count = 0
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i] + mylist[x]
if sum == target:
count += 1
worklist = []
worklist.append(mylist[i])
worklist.append(mylist[x])
sumlist.append(worklist)
return count, sumlist
list = [0, 5, 4, -6, 2, 7, 13, 3, 1]
print(suminlist(list,4))
Things to point out.
The sumlist variable is defined as a list with no initial values.
When a summation of two values in the passed list equate to the test value, they are placed into a new interim list and then that list is appended to the sumlist list along with incrementing the count value.
Once all list combinations are identified, the count value and sumlist are returned to the calling statement.
Following was the test output at the terminal for your list.
#Dev:~/Python_Programs/SumList$ python3 SumList.py
(2, [[0, 4], [3, 1]])
To split the count value out from the list, you might consider splitting the returned data as noted in the following reference Returning Multiple Values.
Give that a try to see if it meets the spirit of your project.
You can use the itertools module for this job.
my_list = [1, 2, 3, 4]
target = 3
out = [x for x in itertools.combinations(my_list, r=2) if sum(x) == target]
print(out)
>>> [(0, 3), (1, 2)]
If you feel like using a python standard library import is cheating, the the official documentation linked above showcases example code for a "low level" python implementation.
Issue:
The issue for returning one set of possible several sets remains in the first return line (return sumlist). Based on the code, the function will automatically ends the function as the first set of value that their sum is the same as the target value. Therefore, we need to adjust it.
Adjustment:
I add a list(finallist[]) at the begining of the function for collecting all the applicable sets that can sum up to the target value. Then, I add a list(list[]) right after the if statement (*since I create an empty list(list[]) right after the if statement, when any sum of two values fulfills the target value, the function will empty the list again to store the new set of two values and append to the finallist[] again). Hence, as long as a set of two numbers can sum up to the target value, we can append them to the list(list[]). Accordingly, I add two more lines of code to append two values into the list(list[]). At the end, I append this list(list[]) to finallist[]. Also, I move the return statement to the final line and adjust the spacing. After this adjustment, the function will not end right after discovering the first possible set of values. Instead, the function will iterate repeatedly until getting all sets of the values and storing in the finalist[].
Originally, the function puts the return statement (return -1) at the end of the function for the situation that none of the sets can sum up to the target value. However, after the previous adjustment, the original return statement (return -1) will not have the opportunity to function as everything will end in the previous return line (return finallist). Therefore, I change it to the else part in the if statement (*meaning: when none of the sum of two values adds up to the target value, we will return 'No two values in the list can add up to the target value.')
Changes in Function:
def suminlist(mylist,target):
# count = 0 # delete
# while count < len(mylist): # delete
finallist=[] # add
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i]+mylist[x]
# count = count + 1 # delete
if sum == target:
# sumlist = mylist[i],mylist[x] # delete
# return sumlist # delete
list=[] # add
list.append(mylist[i]) # add
list.append(mylist[x]) # add
finallist.append(list) # add
else: # add
return 'No two values in the list can add up to the target value.' # add
return finallist # add
# return -1 # delete
Final Version:
def suminlist(mylist,target):
finallist=[]
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i]+mylist[x]
if sum == target:
list=[]
list.append(mylist[i])
list.append(mylist[x])
finallist.append(list)
else:
return 'No two values in the list can add up to the target value.'
return finallist
Test Code and Output:
list = [0, 5, 4, -6, 2, 7, 13, 3, 1]
print(suminlist(list,100))
# Output: No two values in the list can add up to the target value.
print(suminlist(list,4))
# Output: [[0, 4], [3, 1]]
First, I want to find the highest number in the list which is the second number in the list, then split it in two parts. The first part contains the 2nd highest number, while the second part contains the number from the list that sums to the highest number. Then, return the list
eg: input: [4,9,6,3,2], expected output:[4,6,3,6,3,2] 6+3 sums to 9 which is the highest number in the list
Please code it without itertools.
python
def length(s):
val=max(s)
s.remove(val)
for j in s:
if j + j == val:
s.append(j)
s.append(j)
return s
Here's what I have but it doesn't return what the description states.
Any help would be appreciated as I spent DAYS on this.
Thanks,
The main issue in your code seems to be that you are editing the list s whilst iterating through it, which can cause issues with the compiler and is generally just something you want to avoid doing in programming. A solution to this could be iterating through a copy of the original list.
The second problem is that your program doesn't actually find the second biggest value in the list, just a value which doubles to give you the biggest value.
The final problem (which I unfortunately only noticed after uploading what I thought was a solution) is that the split values are appended to the end of the list rather than to the position where originally the largest value was.
Hopefully this helps:
def length(array):
val = max(array)
idx = array.index(val) # gets the position of the highest value in the array (val)
array.remove(val)
for i in array.copy(): # creates a copy of the original list which we can iterate through without causing buggy behaviour
if max(array) + i == val:
array = array[:idx] + [max(array), i] + array[idx:]
# Redefines the list by placing inside of it: all values in the list upto the previous highest values, the 2 values we got from splitting the highest value, and all values which previously went after the highest value.
return array
This will return None if there is no value which can be added to the second highest value to get the highest value in the given array.
Input:
print(length([1,2,3,4,5]))
print(length([4,8,4,3,2]))
print(length([11,17,3,2,20]))
print(length([11,17,3,2,21]))
Output:
[1, 2, 3, 4, 4, 1]
[4, 4, 4, 4, 3, 2]
[11, 17, 3, 2, 17, 3]
None
Here are the docs on list slicing (which are impossible to understand) and a handy tutorial.
when you say "The first part contains the 2nd highest number" does that mean second highest number from the list or the larger of the two numbers that add up the largest number from list?
Here I assume you just wanted the larger of the two numbers that add up to the largest number to come first.
def length(s:list):
#start by finding the largest value and it's position in the list:
largest_pos = 0
for i in range(len(s)):
if s[i] > s[largest_pos]:
largest_pos = i
# find two numbers that add up to the largest number in the s
for trail in range(len(s)):
for lead in range(trail, len(s)):
if (s[trail] + s[lead]) == s[largest_pos]:
if s[trail] > s[lead]:
s[largest_pos] = s[trail]
s.insert(largest_pos +1, s[lead])
else:
s[largest_pos] = s[lead]
s.insert(largest_pos + 1, s[trail])
return s
# if no two numbers add up to the largest number. return s
return s
Since you are limited to 2 numbers, a simple nested loop works.
def length(s):
val = max(s)
idx = s.index(val)
s.remove(val)
for i in range(len(s) - 1):
for j in range(i + 1, len(s)):
if s[i] + s[j] == val:
s = s[:idx] + [s[i], s[j]] + s[idx:]
return s
print(length([4,9,6,3,2]))
Output:
[4, 6, 3, 6, 3, 2]
I used deque library
first to find the highest element or elements then remove all of them and replace them with second high value and rest like : 9 replace with 6 and 3 in example:
from collections import deque
l = [4, 9, 6, 3, 2]
a = deque(l)
e = a.copy()
s = max(a)
while s in a:
a.remove(s) # remove all highest elements
s2 = max(a) # find second high value
c = s - s2
for i in l:
if i == s:
w = e.index(i) # find index of high values
e.remove(max(e))
e.insert(w, s2)
e.insert(w+1, c)
print(list(e))
I'm still something of a beginner with Python and I was trying to optimise a function to generate the Fibonacci sequence to a specified number of values. This is the code I have written:
def attempt2(length):
listy=[]
for i in range(0,length+1):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i]+listy[i-1])
return listy
Whilst keeping this structure I have found no way to overcome the 'list index out of range' error. I think because the listy[i-1] would be out of range when i = 0, but if the function progresses through the loop linearly then the else statement should only take effect when i = 2. Can anyone see what I'm doing wrong?
Thanks!
So, to find out the source of your issue, we need to take a step back to see what your loop is doing.
Initially, your for-loop is counting from 0 to whatever the length is, let's see what the values for i will look like:
0
1
2
...
so starting from 2, since the behavior of 0,1 is defined:
listy.append(listy[2]+listy[1])
Remember that listy has 2 items now, which are zero indexed, in other words the items are 1 and 0, hence the item listy[2] doesn't exist.
Thus, your code should be
listy.append(listy[i-2]+listy[i-1])
It's not a good solution overall but the tiny mistake is that you should change line 9 to:
listy.append(listy[i - 1] + listy[i - 2])
Also you'll have a `length + 1` size list not `length`.
You are using wrong list indices
def attempt2(length):
listy=[]
for i in range(0,length):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i -1]+listy[i - 2])
return listy
print(attempt2(12))
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
Listy[-1] returns the last element of your list.
List position is initialising at 0 not 1.
When i = 2, in your else statement
listy.append(listy[i]+listy[i-1]) is equivalent to listy.append(listy[2]+listy[1])
Yet, your list after the second loop is equal to [1,1].
The max pos is 1 and 2 is out of range.
def loop_fib(n):
# first two numbers are 1
fib_1=1
fib_2=1
res=[1,1]
# n is inclusive
for i in range(3,n+1):
# new fib_2=fib_1+fib_2
# new fib_1=old fib_2
fib_1,fib_2=fib_2,fib_1+fib_2
res.append(fib_2)
return res
loop_fib(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
My task is to remove all instances of one particular element ('6' in this example) and move those to the end of the list. The requirement is to traverse a list making in-line changes (creating no supplemental lists).
Input example: [6,4,6,2,3,6,9,6,1,6,5]
Output example: [4,2,3,9,1,5,6,6,6,6,6]
So far, I have been able to do this only by making supplemental lists (breaking the task's requirements), so this working code is not allowed:
def shift_sixes(nums):
b = []
c = 0
d = []
for i in nums:
if i == 6:
b.insert(len(nums),i)
elif i != 6:
c = c +1
d.insert(c,i)
ans = d + b
return ans
I've also tried list.remove() and list.insert() but have gotten into trouble with the indexing (which moves when I insert() then move the element to the end): For example -
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in nums:
if i == 6:
nums.remove(i)
nums.insert(nums[len(nums)-1], 0)
elif i != 0:
i
shift_sixes(a)
Additionally, I have tried to use the enumerate() function as follows, but run into problems on the right hand side of the b[idx] assigment line:
for idx, b in enumerate(a):
a[idx] = ???
Have read other stackoverflow entries here, here and here, but they do not tackle the movment of the element to one end.
Would appreciate any help on this list traversal / inplace switching issue. Many thanks.
EDIT
#eph - thank you. this is indeed an elegant response. I am sure it will pass my 'no new list' requirement? I surely intend to learn more about lambda and its uses
#falsetru - thank you for the reminder of the append/pop combination (which I tried to do in my original query via list.remove() and list.insert()
#tdelaney - thank you as well. somehow your response is closest to what I was attempting, but it seems not to pass the test for [0, 0, 5].
It is a bad idea to modify list while traverse. You can either make a copy to traverse, or generate a new list during traverse.
In fact, the question can be done in many ways, such as:
>>> a.sort(key = lambda i: i == 6)
>>> a
[4, 2, 3, 9, 1, 5, 6, 6, 6, 6, 6]
Iterating the list reverse way, pop the element if it's 6, then append it.
xs = [6,4,6,2,3,6,9,6,1,6,5]
for i in range(len(xs)-1, -1, -1): # 10 to 0
if xs[i] == 6:
xs.append(xs.pop(i))
Why not try something like this?
Basically, the approach is to first count the number of values.
If 0, then returns (since Python produces a ValueError if the list.index method is called for an element not in the list).
We can then set the first acceptable index for the value to be the length of the list minus the number of occurrences it exists in the list.
We can then combine list.pop/list.append to then traverse the list until all the values desired occur at the end of the list.
def shift_value(lst, value):
counts = lst.count(value) # 5
if not counts:
return lst
value_index = len(lst) - counts
index = lst.index(value)
while index != value_index:
lst.append(lst.pop(index))
index = lst.index(value)
return lst
lst = [6,4,6,2,3,6,9,6,1,6,5]
print(shift_value(lst, 6))
EDIT: This is horribly inefficient, better answer suggested above.
This requires O(n^2) time, rather than O(n) time.
The key term here is "In Line". The way you do that is move num[i] = num[i+1] for each i to the end of the list.
def shift_sixes(num):
for i, val in enumerate(num):
if val == 6:
# shift remaining items down
for j in range(i,len(num)-1):
num[j] = num[j+1]
# add 6 at the end
num[-1] = 6
return num
print(shift_sixes([1,9,4,6,2,7,8,6,2,2,6]))
print(shift_sixes([1,2,3]))
print(shift_sixes([6]))
print(shift_sixes([3]))
Use two runners. First from front to end checking for 6s, second from end to front pointing to last item that's not a 6. Keep swapping (a[i+1], a[i] = a[i], a[i+1]) until they meet.
Catch: this is not stable like in a stable sort. But I don't see that as a requirement.
Will try to write working code when in front of a python interpreter with a keyboard.
In case you need a stable sort (i.e. order of elements that are not 6 should remain the same), then the solution is:
def move_to_end(data, value):
current = 0 # Instead of iterating with for, we iterate with index
processed = 0 # How many elements we already found and moved to end of list
length = len(data) # How many elements we must process
while current + processed < length: # While there's still data to process
if data[current] == value: # If current element matches condition
data.append(data.pop(current)) # We remove it from list and append to end
processed += 1 # Our index remains the same since list shifted, but we increase number of processed elements
else: # If current element is not a match
current += 1 # We increase our index and proceed to next element
if __name__ == '__main__':
print
print 'Some testing:'
print
for test_case in (
[1, 9, 4, 6, 2, 7, 8, 6, 2, 2, 6], # Generic case
[6, 6, 6, 6], # All items are 6
[1, 7], # No items are 6
[], # No items at all
):
print 'Raw:', test_case
move_to_end(test_case, 6)
print 'Becomes:', test_case
print
Note that this solution retains the order of not only non-matching elements, but of matching elements as well. So for example, if you change the check condition from "equal to 6" to "is an even number", all elements matching the condition will be moved to the end of list while retaining their order among themselves.
Why not keep it simple?
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in range(0,len(nums)):
if nums[i] == 6:
nums.append(nums.pop(i))
>>> shift_sixes(a)
>>> a
[3, 9, 1, 5, 2, 4, 6, 6, 6, 6]
I'm writing a program to iterate through a long number, converting it into a string, and then using an index list to pick out 10 individual consecutive numbers from the long number, then multiplying those ten numbers together and adding the numbers and the result to a dictionary. Then I am increasing the index list values by 1, and repeating the process until I have run through the whole number.
Then I am trying to find the largest value in the dictionary, and have the program tell me that value.
The problem I am having is that I have an error checking mechanism in the program, which tells me how many key/value pairs I have in the dictionary. It should be 990, but instead I have 53.
If anyone can identify what the problem is, I will be eternally grateful.
Code to follow:
from functools import reduce
#define the number to test
testno = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
#declare initial variables
index=[]
products = {}
count = 0
#define functions
def product(x):
return reduce((lambda a,b: a*b),x)
def increm(y):
return [x+1 for x in y]
#def runproduct(x):
# return product
def testnos(x):
return [int(str(x)[y]) for y in index]
#define the initial index
for x in range(10):
index = index+[x]
runtime = len(str(testno))-10
#start the while loop
while count < runtime:
products[str(testnos(testno))] = product(testnos(testno))
index = increm(index)
count+=1
print("[+] Number of results: "+str(len(str(products.values))))
print("[+] The numbers with the largest product are: "+str(max(products.keys(),key=(lambda k:products[k]))))
You have a problem in your first print statement. You are currently converting your products into a string, which returns to you something like this
{'[0, 8, 1, 3, 5, 3, 3, 6, 2, 7]': 0, ..., '[7, 8, 4, 6, 8, 6, 2, 2, 4, 8]': 8257536}
Applying the len built-in over it will return the result 53. What you really want here is calling len directly over you products variable.
>>> print("[+] Number of results: {}".format(len(products)))
[+] Number of results: 990
Consider using the format function when building your string. You can use PyFormat website as reference.