python : I want to avoid using 'copy' module - python

(The code below is not a working code. It's just to convey ideas)
My intention is to recursively call sumsubset(arr.remove(el),num,org), parsing updated arr.
However, this will cause unwanted removal to original arr which will cause error. So, I often depend on copy module, feeling somewhat awkward.
Is there any better way parsing updated arr without using copy module?
Thanks for answering my first question.
arr=[1, 1, 2, 4, 4, 4, 7, 9, 9, 13, 13, 13, 15, 15, 16, 16, 16, 19, 19, 20]
num=36
import copy
def sumsubset(arr,num,org):
for el in arr:
if el==org: return [el]
tmp=copy.copy(arr)
tmp.remove(el)
result=[el]+sumsubset(tmp,num-el,org)
return result
a=sumsubset(arr,36,36)

tmp = arr[:]
or
tmp = list(arr)
Both would create a new object, not just copying the reference to the original arr.

Related

Long lists always end with an ellipsis in debug terminal or when copying

In the VS Code debug console or the Variable explorer(?) or the watch list pane(?) long lists always end with an ellipsis when displayed. What is really annoying is a right-click-copy also ends up with the ellipsis in the clipboard.
→ a = list(range(16))
→ a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ...]
Is there any way to alleviate that and copy or display the entire list? Printing then copying works in the debug console but what about the variable and watch list panes/views?
→ print(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
According to your description, I reproduced this problem:
Thank you for posting this problem here, and we have already submitted this question, let us look forward to the improvement of this function.
Github link: When debugging python in VSCode, the variable bar cannot display the complete value of the variable.

This particular way of using .map() in python

I was reading an article and I came across this below-given piece of code. I ran it and it worked for me:
x = df.columns
x_labels = [v for v in sorted(x.unique())]
x_to_num = {p[1]:p[0] for p in enumerate(x_labels)}
#till here it is okay. But I don't understand what is going with this map.
x.map(x_to_num)
The final result from the map is given below:
Int64Index([ 0, 3, 28, 1, 26, 23, 27, 22, 20, 21, 24, 18, 10, 7, 8, 15, 19,
13, 14, 17, 25, 16, 9, 11, 6, 12, 5, 2, 4],
dtype='int64')
Can someone please explain to me how the .map() worked here. I searched online, but could not find anything related.
ps: df is a pandas dataframe.
Let's look what .map() function in general does in python.
>>> l = [1, 2, 3]
>>> list(map(str, l))
# ['1', '2', '3']
Here the list having numeric elements is converted to string elements.
So, whatever function we are trying to apply using map needs an iterator.
You probably might have got confused because the general syntax of map (map(MappingFunction, IteratorObject)) is not used here and things still work.
The variable x takes the form of IteratorObject , while the dictionary x_to_num contains the mapping and hence takes the form of MappingFunction.
Edit: this scenario has nothing to with pandas as such, x can be any iterator type object.

Replace entry in specific numpy array stored in dictionary

I have a dictionary containing a variable number of numpy arrays (all same length), each array is stored in its respective key.
For each index I want to replace the value in one of the arrays by a newly calculated value. (This is a very simplyfied version what I'm actually doing.)
The problem is that when I try this as shown below, the value at the current index of every array in the dictionary is replaced, not just the one I specify.
Sorry if the formatting of the example code is confusing, it's my first question here (Don't quite get how to show the line example_dict["key1"][idx] = idx+10 properly indented in the next line of the for loop...).
>>> import numpy as np
>>> example_dict = dict.fromkeys(["key1", "key2"], np.array(range(10)))
>>> example_dict["key1"]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> example_dict["key2"]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> for idx in range(10):
example_dict["key1"][idx] = idx+10
>>> example_dict["key1"]
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> example_dict["key2"]
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
I expected the loop to only access the array in example_dict["key1"], but somehow the same operation is applied to the array stored in example_dict["key2"] as well.
>>> hex(id(example_dict["key1"]))
'0x26a543ea990'
>>> hex(id(example_dict["key2"]))
'0x26a543ea990'
example_dict["key1"] and example_dict["key2"] are pointing at the same address. To fix this, you can use a dict comprehension.
import numpy
keys = ["key1", "key2"]
example_dict = {key: numpy.array(range(10)) for key in keys}

The folding of ternary operator in a list

The following code is available (demo)
f=lambda m, x:m and(x&1 and m.pop(0)or m.pop(0)[::-1])+f(m, x+1)
print(f([[4, 3, 2, 1], [5, 6, 7, 8], [12, 11, 10, 9], [13, 14, 15, 16]],0))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Here there is logic:
m.pop(0) if x&1 else m.pop(0)[::-1]
Please explain why when folding to the following view, is the code not executing correctly?
[m.pop(0)[::-1],m.pop(0)][x&1]
I don't know much about Python, will be grateful for any help, thank you.
UPD: If I change the logic, I get this result:
f=lambda m,x:m and([m.pop(0)[::-1],m.pop(0)][x&1])+f(m,x+1)
print(f([[4, 3, 2, 1], [5, 6, 7, 8], [12, 11, 10, 9], [13, 14, 15, 16]],0))
# [1, 2, 3, 4, 13, 14, 15, 16]
PS. Code-golf (If this is important, the essence of the code is that it bypasses the two-dimensional array in the form of a snake)
Solution:
[m.pop(0)[::-1],m.pop(0)][x&1] => (lambda: m.pop(0)[::-1], lambda: m.pop(0))[x&1]().
https://ideone.com/u6Qp4O
The issue is that the trinary if only evaluates one of its branch so only one pop call occurs. In your code there are two pop calls that both are evaluated.
[m.pop(0)[::-1], m.pop(0)][x&1]
To avoid that, if one must write it this way, and not using an a trinary A if C else B, one has to thunk, lambda:, each case and then after indexing the list of cases, call the case that was selected:
[lambda: m.pop(0)[::-1], lambda: m.pop(0)][x&1]()
One then could remove the common expression:
item = m.pop(0)
[lambda: item[::-1], lambda: item][x&1]()
Doing this before thunking, would result in:
item = m.pop(0)
[item[::-1], item][x&1]
This would not produce an error if item was slice-able. But it would uselessly produce and discard a reversed copy of item. But if the item is say an int when x is odd and a list when even this would result in an error:
>>> 3[::-1]
TypeError: 'int' object has no attribute '__getitem__'
Because all sub expressions in an expression are evaluated unless they have been delayed by a lambda.
A thunk is a term for a function that takes no arguments.
The short-circuiting behavior is different between all three versions of the expression given (if certain elements of m are false). The a and b or c idiom was commonly used before Python had a conditional operator, but is inequivalent if b is false.

Why does the value of this array change when passed into a function as an argument?

I'm having a problem where when I pass an array into a function, the original value of the array is changed. My example below should clarify what I mean.
So if I have the falling example:
def swap(array):
while True:
noChange = True
for i in range(len(array) - 1):
if array[i] > array[i + 1]:
array[i], array[i + 1] = array[i + 1], array[i]
noChange = False
if noChange:
return array
def baseline(array):
array = sorted(array)
return array
array = [20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0]
sortedArray = swap(array)
print array # Result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
array = [20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0]
sortedArray = baseline(array)
print array # Result: [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
From above, you can see that for some reason, array has been changed when the function called swap is run but when I run baseline. In the function called swap, I've tried re-naming all instances of array to localArray to see if it made a difference but I'm still having the same problem.
I'm sure this is something very obvious that I've over looked but would somebody be able to explain why this is happening?
When you pass the list array to a function, the argument reference to the same list object, if it's modified inside the function, the original list is modifed as well.
If this is not what you want, copy the list in the beginning of the function:
def swap(array):
array = array[:]
# ...
When you pass a list to a function, you are passing the reference to it, hence if you change the list inside the function it will also get changed, you can send a shallow copy of the list (as the list only contains integers) as the argument, so that it does not get changed.
When calling the function do -
import copy
sortedArray = swap(copy.copy(array))
Another way to do it would be to copy the array inside your function, Example -
import copy
def swap(array):
array = copy.copy(array)
When your list contains references to other mutable objects, you should use copy.deepcopy() function (If you will be making changes inside the objects, but you do not want the same changes to reflect to the objects in the original list).

Categories