Function Adding Two Lists - python

EDIT: Thank you for the responses, which are helpful, but I'm not sure they're getting at the core of my problem. In some cases it would be nice to simply select the lower of the lists and then add the values accordingly, but in THIS case I actually want to treat uneven lists as though the shorter list had zero values for the values it was missing. So I want [1, 2, 3] + [1, 2] to function as [1, 2, 3] + [1, 2, 0]. I don't think zip, or reversing my operator, will accomplish this.
I'm trying to create a function that adds the corresponding values of two lists and returns a new list with the sums of each of the indices of the two original lists:
def addVectors(v1, v2):
print(v1[0], v1[1], v2[0])
newVector = []
if len(v1) > len(v2):
for index in range(len(v1)):
print(index)
newVector[index] += v1[index] + v2[index]
else:
for index in range(len(v2)):
print(index)
newVector[index] += v2[index] + v1[index]
return newVector
addVectors([1, 2, 3], [1, 2])
Yet I'm getting an error stating that the list index is out of range? Not sure what I'm doing wrong in this seemingly simple program....

You probably meant to change the line:
if len(v1) > len(v2):
to:
if len(v1) < len(v2):
That way, you are iterating to the number of elements in v1 when v1 is shorter, which prevents you from going over the edge.
Note that this would also throw an error because newVector is a list of length 0 and you are accessing outside of its range. You'd have to change
newVector[index] += v1[index] + v2[index]
to
newVector.append(v1[index] + v2[index])
However, note that this can be done much more simply as:
def addVectors(v1, v2):
return map(sum, zip(v1, v2))
ETA: To pad the list with zeros, do:
import itertools
def addVectors(v1, v2):
return map(sum, itertools.izip_longest(v1, v2, fillvalue=0))
For example:
addVectors([1, 2, 3, 4, 5], [1, 2])
# [2, 4, 3, 4, 5]

Why not just use this?
def sum_lists(a, b):
return [x[0] + x[1] for x in zip(a, b)]
sum_lists([1, 2, 3], [4, 5, 6]) # -> [5, 7, 9]

You compare the lengths of the list, which is correct. But then you change the required operations. I.e. when list1 is longer than list2, you should only loop over the elements for the length of list2.

To fill the lists of uneven length, you can use itertools:
>>> import itertools
>>> map(sum, itertools.izip_longest([1,2,3], [1,2], fillvalue = 0))
[2, 4, 3]

Your problem lies here:
if len(v1) > len(v2):
for index in range(len(v1)):
print(index)
newVector[index] += v1[index] + v2[index]
You ensure that len(v1) > len(v2), but then iterate over range(len(v1)).
In your example, you're trying to access v2[2], which doesn't exist.
UPDATE:
In response to your edit, you could use something like this:
def addVectors(v1, v2):
if len(v1) > len(v2):
map(sum, zip(v1, v2)).extend(v1[len(v2):])
else:
map(sum, zip(v1, v2)).extend(v2[len(v1):])

Your IndexError is because you're trying to write to newVector[index] when newVector is an empty list. You need to either initialize it to a bunch of zeros, or use append instead.
>>> first = [1,2,3]
>>> second = [1,2]
>>> output = []
>>> for i, item in enumerate(first):
... additional = second[i] if i < len(second) else 0
... output.append(item + additional)
...
>>> output
[2, 4, 3]
And to ensure that len(first) > len(second), you can do something like this:
first, second = first, second if len(first) > len(second) else second, first

Or you can try
def add_vector(vector1, vector2):
index = len(vector1) - 1
new = []
while index >= 0:
result = vector1[index] + vector2[index]
new.append(result)
index -=1
new.reverse()
return new

Related

How can I use recursion to add two lists together?

For example, say I have
a = [1, 3, 9]
b = [1, 2, 4, 5]
and I want to return a new list(n) in sequential order:
n = [1,1,2,3,4,5,9] by using recursion.
I have tried doing this using a standard recursion method but my issue is that whenever I create a new list inside the recursive function, its value is always set to [] again during the recursive call. Is there any way to have n not go back to being empty?
def recur(a,b):
if a[0] <= b[0]:
n.append(a[0])
return (merge(a[1:], b))
One way (off the top of my head, may have mistakes):
def merge_sorted(a, b):
if not a:
return b
if not b
return a
if a[0] < b[0]:
return [a[0]] + merge_sorted(a[1:], b)
return [b[0]] + merge_sorted(a, b[1:])
I suggest implementing a few versions, and try finding some yourself, if learning recursion is your goal. One version could be similar to what you started - returning the result in a 3d list (so you would need a 3d argument. The other option is a global which i don't like personally). The recipe for me is always the same:
Define the stop condition. In the above, obviously if one of the inputs is empty, and the other is sorted, than the other one is indeed the result.
From that infer the returning invariant - in the above case is that the result of merge_sorted returns a proper merger of the lists.
Given the invariant, construct the recursive call reducing the size of the input.
This is very similar to proof by induction (identical?).
You can do this:
def recur(array):
ret = []
if len(array) <= 1:
return array;
half = int(len(array) / 2)
lower = recur(array[:half])
upper = recur(array[half:])
lower_len = len(lower)
upper_len = len(upper)
i = 0
j = 0
while i != lower_len or j != upper_len:
if( i != lower_len and (j == upper_len or lower[i] < upper[j])):
ret.append(lower[i])
i += 1
else:
ret.append(upper[j])
j += 1
return ret
a = [1, 3, 9]
b = [1, 2, 4, 5]
print(a+b) #[1, 3, 9, 1, 2, 4, 5]
print(recur(a+b)) #[1, 1, 2, 3, 4, 5, 9]
a = [1, 3, 9]
b = [1, 2, 4, 5]
c=[]
def recurse(a,b,c):
if len(a)==0 and len(b)==0:
pass
elif len(a)==0 and len(b)!=0:
c.extend(b)
elif len(a)!=0 and len(b)==0:
c.extend(a)
elif a[0]<b[0]:
c.append(a[0])
del a[0]
recurse(a,b,c)
else:
c.append(b[0])
del b[0]
recurse(a,b,c)
recurse(a,b,c)
Explanation:
1.Create an empty list c
2.1st If: if both 'a' & 'b' are empty, your recursion is complete
3.1st elif:If only 'a' is empty, extend() all value of 'b' to 'c' & recursion complete
4.2nd elif: similar to 1st elif but vice versa
5.If both are non-empty, check for 1st element of 'a' & 'b'. Whichever is lower, append to 'c' & delete, recursively call 'recurse'
Though it considers both 'a' & 'b' are sorted as in the example above

Filtering the duplicates in subset sum combinations

Given an array, I've found all the combinations of subsets that equal a targeted sum, that's because I want the largest array possible.
For instance, the array [1, 2, 2, 2] for the target sum of "4" returns [[2, 2], [2, 2], [2, 2]].
subsets = []
def subset_sum(numbers, target, partial=[]):
s = sum(partial)
if s == target:
subsets.append(partial)
if s >= target:
return
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i + 1:]
subset_sum(remaining, target, partial + [n])
subsets.sort()
subsets.reversed()
How can I remove values that are once mentioned in the subsets' list?
In the example above, how can I hay only one [2,2].
And that, show the values of the initial array that are not in this final list?
In the example above [1].
You can use itertools.groupby to remove duplicate lists:
>>> import itertools
>>> lst = [[2, 2], [2, 2], [2, 2]]
>>> lst.sort()
>>> new_lst = list(k for k,_ in itertools.groupby(lst))
>>> print(new_lst)
[[2, 2]]
Then simply flatten new_lst with itertools.chain.from_iterable and check if any of the elements from the initial list do not exist in this flattened list:
>>> initial = [1,2,2,2]
>>> print([x for x in initial if x not in itertools.chain.from_iterable(new_lst)])
[1]
Note: You can probably make your subset_sum() return a list of non duplicate items also, but the above should also work fine.
This is not a direct answer to your question, but a better algorithm. If you're only looking for one example of a list of maximal length which satisfies your sum criterion, you should be looking at longer lists first. This code uses itertools for the combinatorial bits and will stop when the longest list is found.
numbers = [1, 2, 2, 2]
taget = 5
for size in reversed(range(1, 1 + len(numbers))):
for c in itertools.combinations(numbers, size):
if sum(c) == target:
break
else:
continue
break
c now contains the longest subset as a tuple (1, 2, 2)
You can do something like this:
Data is :
data=[1, 2, 2,2]
import itertools
your_target=4
One line solution:
print(set([k for k in itertools.combinations(data,r=2) if sum(k)==your_target]))
output:
{(2, 2)}
or better if you use a function:
def targeted_sum(data,your_target):
result=set([k for k in itertools.combinations(data,r=2) if sum(k)==your_target])
return result
print(targeted_sum(data,4))

how to fix the sort function

def merge (l1,l2):
if l1 and l2:
if l1 == [] and l2 == []:
return []
if l1[0] > l2[0]:
l1, l2 = l2, l1
return [l1[0]] + merge(l1[1:], l2)
return l1 + l2
def sort(l):
x = len(l) / 2
x = int(x)
y = merge(l[0:x], l[x+1:])
return y
I need to write a recursive function named sort; it is passed any unordered list (all int or all str) and it returns a new list that contains every value from its argument list, but in sorted/non-descending order. But I cannot call any of Python’s functions/methods that perform sorting.
also, For any list that has at least 2 values, I have to break the list in half and recursively call sort to sort each smaller list, I have to use the merge function, written above, to merge these two sorted lists returned from these recursive calls
merge is a function to combine and sort two list
merge([1,3,5,8,12],[2,3,6,7,10,15]) returns [1,2,3,3,5,6,7,8,10,12,15].
For example, calling sort([4,5,3,1,6,7,2]) would call sort recursively on the lists [4,5,3] and [1,6,7,2]), returning the lists [3,4,5] and [1,2,6,7] respectively, which when merged would return the list [1,2,3,4,5,6,7].
My function got the following error
39 *Error: sort([1,2,3,4,5,6,7]) -> [1, 2, 3, 5, 6, 7] but should -> [1, 2, 3, 4, 5, 6, 7]
40 *Error: sort([7,6,5,4,3,2,1]) -> [3, 2, 1, 7, 6, 5] but should -> [1, 2, 3, 4, 5, 6, 7]
41 *Error: sort([4,5,3,1,2,7,6]) -> [2, 4, 5, 3, 7, 6] but should -> [1, 2, 3, 4, 5, 6, 7]
42 *Error: sort([1,7,2,6,3,5,4]) -> [1, 3, 5, 4, 7, 2] but should -> [1, 2, 3, 4, 5, 6, 7]
What is wrong with me sort method? can someone help me to fix it? thanks in advance.
Three problems:
Your y = merge(l[0:x], l[x+1:]) loses l[x], make it y = merge(l[:x], l[x:]).
It doesn't sort the halves, so make it y = merge(sort(l[:x]), sort(l[x:])).
You have no base case, stopping the recursion when there's nothing to do.
Corrected and simplified a bit:
def sort(l):
if len(l) <= 1:
return l
x = len(l) // 2
return merge(sort(l[:x]), sort(l[x:]))
The // is integer division so you don't need the extra int(...). And no point in creating that y variable.
Btw, the if l1 == [] and l2 == []: test inside if l1 and l2: is pointless (if l1 and l2 were [], you wouldn't get inside the if l1 and l2: block in the first place), so you can remove it.
One more thing: While your merge function isn't wrong, it's slow. Every l1[1:] takes time proportional to the length of l1. You'd better uses indexes, like for example in Huy Vo's answer.
Ok basically everything you're doing is redundant.
list1 = [1,3,5,8,12]
list2 = [2,3,6,7,10,15]
list3 = list1 + list2 # Merges lists
list3_sorted = sorted(list3) # Sorts them
Also a little bonus, if you have a list of lists or tuples and you want to sort by an index of each of those
from operator import itemgetter
list = [(2,6), (3,4)]
list_sorted = sorted( list, key=itemgetter(1) ) # Will sort by index 1 of each item.
Edit: I now realise that you can't use any built in functions, give me a little to mess around and see if I can figure something out
What you need is a merge sort, I believe there are multiple merge sort pseudocodes on the internet.
Anyway, here is a version of mine in Python 3:
def mergesort(lst):
if len(lst) < 2:
return lst
else:
middle = len(lst) // 2
# recursion, baby
left_half = mergesort(lst[:middle])
right_half = mergesort(lst[middle:])
return merge(left_half, right_half)
def merge(left, right):
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
elif left[i] > right[j]:
result.append(right[j])
j += 1
result += left[i:] + right[j:]
return result

Return lists that do not have 1s

I want to create what I thought was a fairly straightforward function. The function just runs through a list of lists and returns any list that does not have a 1 in all of the list elements following the second element ([2: ]). So given the list of lists [[1, 2, 1, 1, 1, 1], [4, 5, 1, 2, 0.3, 1, 1, 1]] the function would return [4, 5, 1, 2, 0.3, 1, 1, 1]. What I have so far is:
def discover(A):
"""Looks for list that has an element not equal to one.
"""
for i in range(len(A)):
for j in range(len(A[i])):
if A[i][j+2] != 1:
print A[i]
But when I run the function it finds one list but then prints that list over and over again before giving me an IndexError saying the list index is out of range. This seems to be a fairly easy problem but for some reason I'm not getting it. Any help would be really appreciated.
The problem is these two lines:
for j in range(len(A[i])):
if A[i][j+2] != 1:
What'll happen is that you'll eventually get to a point where j is the length of your list, minus 1. But then you're calling j+2 in the below code, and that's guaranteed to create a number longer than your list, giving you the IndexError. You can fix that with:
for j in range(2,len(A[i])):
if A[i][j] != 1:
As for the endless printing, you're nearly there, but you'll want to stop the loop if you find the non-1 element.
if A[i][j] != 1:
print A[i]
break
Alternately, the other answers will give you the same result more easily. But that's where your current errors are coming from.
for list in A:
if 1 not in list[3:]:
print list
even another solution:
lst = [
[1,2,3],
[1,1,1],
[3,4,5],
[3,5,6],
] # +++
def has1(subLst):
return subLst.count(1) == 0
print filter(has1, lst)
This avoids out of range issues.
def discover(A):
results = []
for lst in A:
for i in lst[3:]:
if i != 1:
results.append(lst)
break
return results
In addition to the other answers here, one could also make use of a generator. The yield statement will allow you to skirt establishing a default list to place your results into; you can just specify the condition you're looking for and yield the result.
>>> def discover(lists):
... for l in lists:
... if not [x for x in l[2:] if x != 1]:
... yield l
>>> stuff = [[2, 3, 4, 5, 1, 2], [2, 5, 1, 1, 1, 1, 1]]
>>> results = discover(stuff) #returns <generator object discover at 0x105e3eb90>
>>> results.next()
[2, 5, 1, 1, 1, 1, 1]
>>>
The magic line here being, if not [x for x in l[2:] if x !=1]. It builds a list from l[2:] and checks that any variable in there does not equal 1; if the list has no length, it means there are no non-1 entries in l[2:] and so it yields l.
A query to check if any element (after the second) != 1 would be:
any(x != 1 for x in mylist[3:])
so
def discover(A):
for mylist in A:
if any(x != 1 for x in mylist[3:]):
print mylist

QuickSort is returning correct values, but not sorting in place

I'm struggling to understand why my QuickSort returns the sorted values correctly, but the resulting array is not sorted correctly.
def qSort(array):
n = len(array)
if (n == 1 or n ==0):
return array
p_index = partition(array)
p_value = array[p_index]
return(qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n]))
def partition(array):
pivot = array[0]
i = 1
for j in xrange(1,len(array)):
print j
if array[j] < pivot:
tmp = array[j]
array[j] = array[i]
array[i]=tmp
i += 1
tmp = array[i-1]
array[i-1] = pivot
array[0] = tmp
return i-1
Here is some sample output:
>>> q = [5,4,3,2,1]
>>> qSort(q)
[1, 2, 3, 4, 5]
>>> q
[1, 4, 3, 2, 5]
Thank you in advance!
In Python, slicing and combining lists create new lists. If you want your recursive calls to operate on a single list in place, pass the list and the bounds into the call, and don't return anything from the function. Something like:
def qsort(array, low, high):
if high-low < 2:
return
# Choose pivot, do partition within bounds
if partition > low:
qsort(array, low, partition)
if partition < high:
qsort(array, partition+1, high)
Then just call qsort(a, 0, len(a)) to sort the array.
This is because you are making up a new list in your return statement.
return(qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n]))
If the qSort function reaches a base case, it returns a list, which is concatenated with [p_value] and returned as a list. You do not make changes to the passed in list anywhere.
When you call your qSort function recursively, you are giving it a slice of the list and the function returns the list in the base case which you then append to the pivot and the other recursive call, hence generating a new list.
See what is happening by changing your qSort function to
def qSort(array):
n = len(array)
if (n == 1 or n ==0):
return array
p_index, array = partition(array)
p_value = array[p_index]
returnVal = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
print "Returning:", returnVal, "Original Array:", array
return returnVal
Output -
>>> q = [5,4,3,2,1]
>>> qSort(q)
Returning: [2, 3] Original Array: [2, 3]
Returning: [2, 3, 4] Original Array: [2, 3, 4]
Returning: [1, 2, 3, 4] Original Array: [1, 4, 3, 2]
Returning: [1, 2, 3, 4, 5] Original Array: [1, 4, 3, 2, 5]
[1, 2, 3, 4, 5]
To reflect the changes in your original list, you have the option of doing q = qSort(q).
P.S - Setting up a random index instead of the first value would be better for your quicksort function. See the bit here on Choice of Pivots.
apply the function back to q
q = qSort(q)
If you want to return the array and also sort in place you should before returning make the array equal to the result and not make a new one. You can do that by changing your return statement to:
array[:] = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
return array
Note that
array = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
does not work either, because the lhs variable will be treated as a local variable.

Categories

Resources