python list is not copying - python

In the following subset problem, I'm trying to make a copy of a list object
def findFourPlus(itemCount, seq, goal):
goalDifference = float("inf")
closestPartial = []
subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial=[])
print(closestPartial)
def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
s = sum(partial)
# check if the partial sum is equals to target
if(len(partial) == itemCount):
if s == goal:
print(partial)
else:
if( abs(goal - s) < goalDifference):
goalDifference = abs(goal - s)
print(goalDifference)
print(partial)
print(closestPartial)
closestPartial = copy.deepcopy(partial)
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])
in the subset function, I am trying to make a copy of the partial list to closestPartial. I've tried
closestPartial = partial
closestPartial = list[:]
closestPartial = list(partial)
closestPartial = copy.copy(partial)
closestPartial = copy.deepcopy(partial)
but in the end all of them seems to be futile. closestPartial remains to be an empty list (which is what I initiated to) for some reason

You are passing closestPartial in as a parameter, so the only thing that will work is an inplace update of its list. All of the examples you give replace the list that was in closestPartial with a new list. But since it wasn't the list you passed in, it doesn't update the real list.
Try:
closestPartial[:] = partial
You can get a feel for the problem by printing the list id before and after the operation.
print id(closestPartial)
...some operation
print id(closestPartial)
if the id changes, that means you created a new list and didn't update the one passed in.
EDIT
Seems I need a better explanation... when you call subset_sum, it creates a local variable called closestPartial that references whatever was passed in as a parameter, in this case a list known to the caller as closestPartial. You now have two variables pointing to the same list. If you reassign the variable, like in closestPartial = partial, those two variables now point to different lists. You didn't update the caller's pointer, you just changed the local variable. Instead, if you don't reassign, changes you make to the one list referenced by both variables are seen by the caller as well - because its the same list.

I suspect that your goalDifference is suffering from the same problem, if you change it in a function and then expect the changed value to somehow get back to the calling function.
Here's some (Python 2 style) code to illustrate what's happening:
#! /usr/bin/env python
def testA(update_func):
seq = []
num = 1
for _ in range(5):
newnum = update_func(seq, num)
print 'testA: ', num, seq, newnum
print
def testB(update_func):
seq = []
num = 1
for _ in range(5):
num = update_func(seq, num)
print 'testB: ', num, seq
print
def update0(seq, num):
#This creates a new list
seq = seq + [num]
num = num + 1
print 'update0:', num, seq
return num
def update1(seq, num):
#This updates the existing list
seq.append(num)
num += 1
print 'update1:', num, seq
return num
def update2(seq, num):
#This updates the existing list
seq[:] = seq + [num]
num += 1
print 'update2:', num, seq
return num
def update3(seq, num):
#This updates the existing list
seq += [num]
num += 1
print 'update2:', num, seq
return num
update_funcs = (update0, update1, update2, update3)
for f in update_funcs:
testA(f)
print '------\n'
for f in update_funcs:
testB(f)
Stack Overflow member Ned Batchelder's article Facts and myths about Python names and values has a good explanation, with cute diagrams.

Related

how do I iterate only once per function call

I have a list of things I want to iterate over and return each of them only once per function call.
What I've tried:
tl = """
zza,zzb,zzc,zzd,zze,zzf,zzg,zzh,zzi,zzj,zzk,zzl,zzm,zzn,zzo,zzp,zzq,zzr,zzs,zzt,zzu,zzv,zzw,zzx,zzy,zzz
"""
# convert each string into list
result = [x.strip() for x in tl.split(",")]
index = 0
def func():
return result[index]
index += 1
It's saying code unreachable at the index += 1 part.
The output I want is zza the first time I call func(), then zzb, then zzc, etc.
Appreciate the help.
EDIT:
I've found this answer to work well and easily readable:
# list of elements seperated by a comma
tl = """
zza,zzb,zzc,zzd,zze,zzf,zzg,zzh,zzi,zzj,zzk,zzl,zzm,zzn,zzo,zzp,zzq,zzr,zzs,zzt,zzu,zzv,zzw,zzx,zzy,zzz
"""
# split each string by comma to get a list
result = [x.strip() for x in tl.split(",")]
# initialize the object
iterator_obj = iter(result)
print(next(iterator_obj))
print(next(iterator_obj))
print(next(iterator_obj))
output:
zza
zzb
zzc
In c++ there is an operator that will increment a variable with ++i incrementing before evaluation and i++ after evaluation
(i:=i+1) #same as ++i (increment, then return new value)
(i:=i+1)-1 #same as i++ (return the incremented value -1)
so the function you want is
def func():
global index
return result[(index := index+1)-1]
the := operator is new in python 3.8
so
tl = """
zza,zzb,zzc,zzd,zze,zzf,zzg,zzh,zzi,zzj,zzk,zzl,zzm,zzn,zzo,zzp,zzq,zzr,zzs,zzt,zzu,zzv,zzw,zzx,zzy,zzz
"""
# convert each string into list
result = [x.strip() for x in tl.split(",")]
index = 0
def func():
global index
return result[(index := index + 1) - 1]
print(func())
print(func())
print(func())
print(func())
prints
zza
zzb
zzc
zzd
Because return statement exit the function, any statement after that is not reachable. A quick fix to your code:
tl = """
zza,zzb,zzc,zzd,zze,zzf,zzg,zzh,zzi,zzj,zzk,zzl,zzm,zzn,zzo,zzp,zzq,zzr,zzs,zzt,zzu,zzv,zzw,zzx,zzy,zzz
"""
# convert each string into list
result = [x.strip() for x in tl.split(",")]
next_index = 0
def func():
global next_index
next_index += 1
return result[next_index-1]
BTW, your func behaves like built-in next. If you don't want to reinvent the wheel:
# convert each string into iterator
result = (x.strip() for x in tl.split(","))
# next(result) will get to the next item on the list
If you want to be able to only return one item of your string at a time per function call, you need to use an generator:
def func(items):
string_list = items.split(",")
for i in range(len(string_list)):
yield string_list[i]
tl = """
zza,zzb,zzc,zzd,zze,zzf,zzg,zzh,zzi,zzj,zzk,zzl,zzm,zzn,zzo,zzp,zzq,zzr,zzs,zzt,zzu,zzv,zzw,zzx,zzy,zzz
"""
item = func(tl)
To pull a value out, in order, use
next(item) # zza
next(item) # zzb
...
Every time you call next, a new value will be returned.
As an aside, anything after return statement will not run, which is why your index += 1 did not work. Return stops the function from running.

Anybody know how to use pyresttest's 'fixed_sequence' generator?

I'm trying to use pyresttest's benchmarking framework to generate a sequence of entries in my flask_sqlalchemy-based database. I would like to read input values from a pre-defined list as advertised by this framework's benchmarking generator type 'fixed_sequence', but it's only picking up the first element of the list.
Here is the issue that explains my problem in detail, with an example: https://github.com/svanoort/pyresttest/issues/264
Any pointer in the right direction will be greatly appreciated
I looked into the code, it is jsut a bug, this feature was never used by anyone.
https://github.com/svanoort/pyresttest/blob/master/pyresttest/generators.py#L100
instead of:
```
def factory_fixed_sequence(values):
""" Return a generator that runs through a list of values in order, looping after end """
def seq_generator():
my_list = list(values)
i = 0
while(True):
yield my_list[i]
if i == len(my_list):
i = 0
return seq_generator
It should be:
def factory_fixed_sequence(values):
""" Return a generator that runs through a list of values in order, looping after end """
def seq_generator():
my_list = list(values)
i = 0
while(True):
yield my_list[i]
i += 1
if i == len(my_list):
i = 0
return seq_generator
```
The i += 1 is missing

File's Data keeps getting overwritten by function

for some reason I am running into an issue where my function call seems to be overwriting the data read in from the file without me asking it to. I am trying to get the sum of the original list but I keep getting the sum of the squared list.
CODE:
def toNumbers(strList):
for i in range(len(strList)):
strList[i] = strList [int(i)]
return strList
def squareEach(nums):
for i in range(len(nums)):
nums[i] = eval(nums[i])
nums[i] = nums[i]**2
return nums
def sumList(nums):
b = sum(nums)
return b
def main():
file=open("numbers.txt","r").readline().split(" ")
print(str(squareEach(file)))
print(str(sumList(file)))
Your squareEach function modifies the original list which is passed to it.
To see what's going, consider adding a print between your function calls.
def main():
file=open("numbers.txt","r").readline().split(" ")
print(str(squareEach(file)))
print(str(file))
print(str(sumList(file))
EDIT:
The simplest fix would be to use a different list for storing your square numbers inside squareEach function
def squareEach(nums):
squares = []
for i in range(len(nums)):
num = eval(nums[i])
squares[i] = num**2
return squares
There are more efficient ways as suggested in other answers, but in your case, this appears to be the simplest fix.
The list nums is modified in squareEach method. Consider storing the results in a different list variable of the below sort:
def squareEach(nums):
sq = list()
for i in range(len(nums)):
sq.append(str(int(nums[i])**2))
# nums[i] = str(int(nums[i])**2)
return sq
I am not sure whether i am helping . But whatever you are trying to do can be done as follows
file=open("numbers.txt","r").readline().split(" ")
print ([int (m)**2 for m in file])
print (sum([int(m) for m in file]))
And if you want functions
def squareEach(file):
print ([int (m)**2 for m in file])
def sumList(file):
print (sum([int(m) for m in file]))
file=open("numbers.txt","r").readline().split(" ")
squareEach(file)
sumList(file)

Recursively Generating a List of n choose k combinations in Python - BUT return a list

I'm attempting to generate all n choose k combinations of a list (not checking for uniqueness) recursively by following the strategy of either include or not include an element for each recursive call. I can definitely print out the combinations but I for the life of me cannot figure out how to return the correct list in Python. Here are some attempts below:
class getCombinationsClass:
def __init__(self,array,k):
#initialize empty array
self.new_array = []
for i in xrange(k):
self.new_array.append(0)
self.final = []
self.combinationUtil(array,0,self.new_array,0,k)
def combinationUtil(self,array,array_index,current_combo, current_combo_index,k):
if current_combo_index == k:
self.final.append(current_combo)
return
if array_index >= len(array):
return
current_combo[current_combo_index] = array[array_index]
#if current item included
self.combinationUtil(array,array_index+1,current_combo,current_combo_index+1,k)
#if current item not included
self.combinationUtil(array,array_index+1,current_combo,current_combo_index,k)
In the above example I tried to append the result to an external list which didn't seem to work. I also tried implementing this by recursively constructing a list which is finally returned:
def getCombinations(array,k):
#initialize empty array
new_array = []
for i in xrange(k):
new_array.append(0)
return getCombinationsUtil(array,0,new_array,0,k)
def getCombinationsUtil(array,array_index,current_combo, current_combo_index,k):
if current_combo_index == k:
return [current_combo]
if array_index >= len(array):
return []
current_combo[current_combo_index] = array[array_index]
#if current item included & not included
return getCombinationsUtil(array,array_index+1,current_combo,current_combo_index+1,k) + getCombinationsUtil(array,array_index+1,current_combo,current_combo_index,k)
When I tested this out for the list [1,2,3] and k = 2, for both implementations, I kept getting back the result [[3,3],[3,3],[3,3]]. However, if I actually print out the 'current_combo' variable within the inner (current_combo_index == k) if statement, the correct combinations print out. What gives? I am misunderstanding something to do with variable scope or Python lists?
The second method goes wrong because the line
return [current_combo]
returns a reference to current_combo. At the end of the program, all the combinations returned are references to the same current_combo.
You can fix this by making a copy of the current_combo by changing the line to:
return [current_combo[:]]
The first method fails for the same reason, you need to change:
self.final.append(current_combo)
to
self.final.append(current_combo[:])
Check this out: itertools.combinations. You can take a look at the implementation as well.

Hash Function in Python generating error

So I am trying to get a grasp on Hash Functions and how exactly they work. I have the following code but I keep getting an error when I try and run the code.
import sys
def part_one():
foo = open('input_table.txt')
for line in foo:
id, make, model, year = line.split(",")
print(make, model)
tuple_list = (make+model,)
return tuple_list
def hash_one(num_buffers, tuple_list):
#part_one()
# A being the first constant prime number to multiply by
# B being the prime number that we add to A*sum_of_chars
tuple_list = part_one()
A = 3
B = 5
count = 0
for item in tuple_list:
for char in item:
# sum_of_chars is the total of each letter in the word
count = ord(char)
count = count + tuple_list
index = ((A * sum_of_chars + B)) % num_buffers
return index
if __name__ == '__main__':
input_table = sys.argv[1]
num_buffers = int(sys.argv[2])
chars_per_buffer = int(sys.argv[3])
sys.argv[4] = 'make'
sys.argv[5] = 'model'
lst = []
for item in range(4, len(sys.argv)):
lst.append(sys.argv[item])
print(lst)
hash_one(lst)
What is wrong with my code that is causing the error? Can anyone help me?
1
You're calling hash() with no arguments, you have to hash something.
A hash of a number will just return the same number though, so it's not very interesting. It's for hashing things like strings.
2
part_one returns nothing, therefore when you call tuple_list = part_one(), it's value is set to None, and you can't iterate though it.
3
Passing in a list through an argument then overwriting it doesn't make any sense anyway. If you want to return a list then use a return statement.
4
It's odd to set argument variables in code, they're for reading things from the command line.
5
(Not an error, but...)
You can use a slice (lst = sys.argv[4:]) as an easier way to get a sub-section of a list.

Categories