I am learning Dynamic Programming from freecodecamp, the instructor is using JavaScript and i know python so i am converting the logic in python.

Long story short, this problem's JavaScript implementation is working fine, but my python implementation is giving strange output.

I have matched the syntax many times and verified the logic, i can't point out where i am going wrong. Any help would be appreciated.

Problem Statement:
Create a program to find the smallest sub-array of integers whose sum is equal to `targetsum`

.

JavaScript Implementation:

```
const bestsum = (targetsum, numbers, memo={}) => {
if (targetsum in memo) return memo[targetsum];
if (targetsum === 0) return [];
if (targetsum <0) return null;
let shortestcomb = null;
for (let num of numbers){
const remainder = targetsum - num;
const remaindercomb = bestsum(remainder, numbers, memo);
if (remaindercomb !== null){
const combination = [...remaindercomb, num];
if (shortestcomb===null || combination.length < shortestcomb.length){
shortestcomb = combination;
}
}
}
memo[targetsum] = shortestcomb;
return shortestcomb;
}
console.log(bestsum(7, [2, 4, 3]));
console.log(bestsum(100, [1, 2, 5, 25]));
```

Output:

```
[ 3, 4 ]
[ 10, 10 ]
```

My Python Implementation:

```
def bestsum(targetsum, arr, memo=None):
if memo is None:
memo={}
if targetsum in memo: return memo[targetsum]
if targetsum==0: return []
elif targetsum < 0: return None
shortest = None
for i in arr:
remainder = targetsum-i
seq = bestsum(remainder, arr, memo)
if seq!=None:
seq.append(i)
if (shortest==None or len(seq)<len(shortest)):
shortest = seq
memo[targetsum] = shortest
return shortest
print(bestsum(7, [2, 4, 3]))
print(bestsum(20, [5, 10]))
```

Output:

```
[4, 3]
[10, 5, 5, 10]
```

The obvious answer for the second case is `[10, 10]`

as that would sum to 20 with the least number of elements, also for the first case the JavaScript output is `[3, 4]`

whereas python output is `[4, 3]`

, isn't it strange?

EDIT: Someone marked this question as duplicate, i followed that guide and used a placeholder in place of the mutable default argument, but the output is still the same, what is wrong now?

·

Juan Pablo Isaza

While an interactive debugger is the most general (and, often, most powerful) way of examining bugs, here a simple bit of scaffolding can reveal much. By adding a `print(f"target = {targetsum}; memo = {memo}")`

statement just before the end of `bestsum`

, we get:

target = 5; memo = {5: [5]} target = 10; memo = {5: [5, 5], 10: [10]} target = 15; memo = {5: [5, 5, 10], 10: [10, 5], 15: [10, 5]} target = 20; memo = {5: [5, 5, 10], 10: [10, 5, 5, 10], 15: [10, 5, 5, 10], 20: [10, 5, 5, 10]}

Note how the entries for each target sum keep changing. This shouldn't happen, based on the algorithm. Looking at `bestsum`

, the entries of `memo`

come from `seq`

. Looking for lines that alter `seq`

, we find `seq.append(i)`

. This mutates the list, which is why the entries of `memo`

keep changing, and why the final result is incorrect. The JavaScript version of `bestsum`

creates a new list for each iteration of the loop body, which is why it doesn't suffer this bug.

Note you could translate the JavaScript directly and use the spread operator, or you could list concatenation: `seq = seq + [i]`

.

One approach that would have prevented this bug from arising would be to use an immutable type instead of a list. In Python, that would be `tuple`

. The one wrinkle is than if using tuple concatenation, a single-element tuple must have a comma trailing the element: `seq = seq + (i,)`

.

·
Juan Pablo Isaza
Report

Expanding on @outis's answer, the entries of `memo`

are changing with each iteration, this shouldn't happen.
This is happening because when you assign a list to a new variable, instead of creating a new list, python refrences the old list's address to the new one.

This creates a problem when the list is changed, as the changes start to show in all its copies.

Here `seq`

is the master list

`shortest`

is copied from `seq`

`memo[targetsum]`

is copied from `shortest`

Ideally after all the children of a recursive tree node are traversed we select the shortest path and assign it to `memo[targetsum]`

but the value inside `memo[target]`

changes with the changes in `seq`

that introduces the unexpected values in `memo`

.

It can be fixed by using an immutable data type as @outis suggested. But we can go a step further and just make a small change to this code itself.

```
import copy
def bestsum(targetsum, arr, memo=None):
if memo is None:
memo = {}
if targetsum in memo: return copy.deepcopy(memo[targetsum])
if targetsum==0: return []
elif targetsum < 0: return None
shortest = None
for i in arr:
remainder = targetsum-i
seq = bestsum(remainder, arr, memo)
if seq!=None:
seq.append(i)
if (shortest==None or len(seq)<len(shortest)):
shortest = seq
memo[targetsum] = copy.deepcopy(shortest)
return shortest
print(bestsum(7, [2, 4, 3]))
print(bestsum(20, [5, 10]))
```

Output:

```
[3, 4]
[10, 10]
```

Here we are using `deepcopy`

from the `copy`

module in python. `deepcopy`

essentially creates a new list and populates it recursively with the elements of the original list, therefore the new lists are totally different from each other. Read more about it here

PS- `deepcopy`

is probably overkill here as it is generally used for nested lists, using shallowcopy will also work fine here.

Shallowcopy syntax-

```
newlist = oldlist.copy()
```

·
Juan Pablo Isaza
Report

Loading