Python append or overwrite list element - python

How do you alternatively append or overwrite a list element in python?
I am currently trying to translate a function I have working in ruby to python, my ruby code looks like such:
def self.push_array_hash(key,selector,level,array)
(0..array.length).each do |i|
x = array[i]
selector[level] = i+1
if(x.is_a?(Array))
self.push_array_hash(key,selector,level+1,x)
end
self.push_datum("#{key}(#{selector.join(',')})", x)
end
end
I am able to call this function as: self.push_array_hash(key,Array.new,0,val) without having to know the dimensions of the nested arrays. The code selector[level] = i+1 easily handles appending an element to the array if selector[level] does not exist yet, and changing the value at level if it does exist.
That is ruby (only given so everyone can understand the what I am aiming for), on to python. Here is my translated code:
def push_list_dict(self, key, selector, level, array):
for i, x in enumerate(array):
selector[level] = i+1
if isinstance(x, (list, set)):
if isinstance(value, set):
value = sorted(value)
self.push_list_dict(key,selector,level+1,x)
self.push_datum(key+"("+",".join(map(str, selector))+")",x)
I call the function as such: self.push_array_dict(key,[],0,value), however it breaks on selector[level] = i+1 and gives me the error: IndexError: list assignment index out of range. Is there an easy way of alternatively appending a value to the array or resetting the value? Thanks,
Joshua

You could use:
selector[level:level+1] = [i+1]
If selector[level] already exists, this replaces the value.
If it does not already exist, it appends the value.
For example,
In [102]: selector = []
In [103]: selector[0:1] = [100]
In [104]: selector
Out[104]: [100]
In [105]: selector[0:1] = [200]
In [106]: selector
Out[106]: [200]
Notice what happens if the index is beyond the length of selector:
In [107]: selector[7:8] = [300]
In [108]: selector
Out[108]: [200, 300]
It does not insert at that index location, it just appends.

Python doesn't magically extend the array the way ruby does. One way is to check the length and pad to the correct length using [None] * x or [0] * x
selector += [None] * (level-len(selector))
selector[level] = i+1
Aside:
range doesn't include the "stop" value, so you may not want the -1 there. The usual way to write this
for i in range(0,len(array)-1):
x = array[i]
...
is
for i, x in enumerate(array):
...

Related

Is there a way to find the 0th index a variable amount of times?

I don't really have a good reason for needing to know this, but is it possible to find the 0th index a certain amount of times? Say like you have this piece of code
ar = [[[["a"]]]]
print(ar[0][0][0][0])
but instead of the 4 [0][0][0][0] you can just do like ar([0]*4). Anyway, thanks for the help.
What you want to do sounds weird because you will rarely run into a situation where you have an unknown nesting structure. That said, a loop is the first thing you should think of when you encounter a problem of the type "do X a bunch of times".
For example, you could set ar to the zeroth element of ar as long as ar is an instance of type list and is also not empty.
ar = [[[["a"]]]]
while isinstance(ar, list) and len(ar) > 0:
ar = ar[0]
print(ar) # output: a
Note: len(ar) > 0 is just for clarity if you're a beginner. Empty lists are falsey, so you could have also just done while isinstance(ar, list) and ar:
You could also specify how many times you can drill down and the index to which you want to drill down:
def drill_down(arg, index, count):
for i in range(count):
if isinstance(arg, list) and len(arg) > index:
arg = arg[index]
return arg
ar = [[[["a"]]]]
result = drill_down(ar)
print(result) # Output: a
Or, you could use a recursive function, which can be made to behave similar to a loop:
def drill_down(arg, index, count):
if isinstance(arg, list) and len(arg) > index and count > 0:
return drill_down(arg[index], index, count - 1)
return arg
ar = [[[["a"]]]]
result = drill_down(ar)
print(result) # Output: a
You can use functools and itertools to define a function that repeatedly indexes into the ith element of an array count times :)
import functools
import itertools
find_nth_elem = lambda n, arr: arr[n]
def repeated_index(arr, i, count):
"""Index into `i`th element of `arr` a total of `count` times."""
# get _an iterator of_ `count` copies of the same function, lazy eval
index_calls = itertools.repeat(functools.partial(find_nth_elem, i), count)
# f(f(f(...f(arr)...))), where f(x) = get nth element of x.
return functools.reduce(lambda acc, f: f(acc), index_calls, arr)
arr = [[[["a"]]]]
print(repeated_index(arr, 0, 4))

Swapping List Elements During Iteration

I have read in several places that it is bad practice to modify an array/list during iteration. However many common algorithms appear to do this. For example Bubble Sort, Insertion Sort, and the example below for finding the minimum number of swaps needed to sort a list.
Is swapping list items during iteration an exception to the rule? If so why?
Is there a difference between what happens with enumerate and a simple for i in range(len(arr)) loop in this regard?
def minimumSwaps(arr):
ref_arr = sorted(arr)
index_dict = {v: i for i,v in enumerate(arr)}
swaps = 0
for i,v in enumerate(arr):
print("i:", i, "v:", v)
print("arr: ", arr)
correct_value = ref_arr[i]
if v != correct_value:
to_swap_ix = index_dict[correct_value]
print("swapping", arr[to_swap_ix], "with", arr[i])
# Why can you modify list during iteration?
arr[to_swap_ix],arr[i] = arr[i], arr[to_swap_ix]
index_dict[v] = to_swap_ix
index_dict[correct_value] = i
swaps += 1
return swaps
arr = list(map(int, "1 3 5 2 4 6 7".split(" ")))
assert minimumSwaps(arr) == 3
An array should not be modified while iterating through it, because iterators cannot handle the changes. But there are other ways to go through an array, without using iterators.
This is using iterators:
for index, item in enumerate(array):
# don't modify array here
This is without iterators:
for index in range(len(array)):
item = array[index]
# feel free to modify array, but make sure index and len(array) are still OK
If the length & index need to be modified when modifying an array, do it even more "manually":
index = 0
while index < len(array):
item = array[index]
# feel free to modify array and modify index if needed
index += 1
Modifying items in a list could sometimes produce unexpected result but it's perfectly fine to do if you are aware of the effects. It's not unpredictable.
You need to understand it's not a copy of the original list you ar iterating through. The next item is always the item on the next index in the list. So if you alter the item in an index before iterator reaches it the iterator will yield the new value.
That means if you for example intend to move all items one index up by setting item at index+1 to current value yielded from enumerate(). Then you will end up with a list completely filled with the item originally on index 0.
a = ['a','b','c','d']
for i, v in enumerate(a):
next_i = (i + 1) % len(a)
a[next_i] = v
print(a) # prints ['a', 'a', 'a', 'a']
And if you appending and inserting items to the list while iterating you may never reach the end.
In your example, and as you pointed out in a lot of algorithms for e.g. combinatoric and sorting, it's a part of the algorithm to change the forthcoming items.
An iterator over a range as in for i in range(len(arr)) won't adapt to changes in the original list because the range is created before starting and is immutable. So if the list has length 4 in the beginning, the loop will try iterate exactly 4 times regardless of changes of the lists length.
# This is probably a bad idea
for i in range(len(arr)):
item = arr[i]
if item == 0:
arr.pop()
# This will work (don't ask for a use case)
for i, item in enumerate(arr):
if item == 0:
arr.pop()

Removing third element from list until there are less than 3 numbers

I have a problem. I need to create a list . And in every iteration i need to remove the third element and print the list without the deleted element.
The thing is. I'm trying to do an algorithm of deleting the third element without remove function or other inbuilt list functions. In my code I covered the following possibilities. If my list has less than 3 elements I print a message saying the list is short. If my list has 3 elements in it I will assign the third element the value of the second element and so on. My problem is when my list has more than 3 elements.
v=[] # list of numbers the user inputs
two=[] #list with only 2 elements
vector=[] # list with third element deleted when len(v)>3
def create_array():
n=int(input('Digit total elements in dynamic array - '))
for i in range(0,n):
element=int(input('Digit element to array - '))
v.append(element)
return v
print(create_array())
def remove_third_element():
for j in range(0,len(v)):
if len(v)<3: # if number of elements in list < 3 there is no element to delete
print('There is no element do delete! ')
return 0
elif len(v)==3:
v[2]==v[1] and v[1]==v[0]
two=[v[0],v[1]]
return two
else:
v[0]==v[1] and v[1]==v[2]
print(remove_third_element())
elif len(v) > 3:
ret = [];
for i in range(len(v)):
if(i != 2) ret.append(v[i]);
return ret
should do the trick
By the way, with this method you can remove you elif len(v) == 3
Also your code :
elif len(v)==3:
v[2]==v[1] and v[1]==v[0]
two=[v[0],v[1]]
return two
won't work because '==' is used as condition in python so it will return a boolean and not assign value.
go for
v[2] = v[1]
v[1] = v[0]
instead
Here's a Pythonic way of making a new list without the original list's third element.
new_list = old_list[:2] + old_list[3:]
old_list[:2] is shorthand for "until the 2-th index" (so we'll get index 0 and 1) of the old_list.
old_list[3:] is shorthand for, "from 3rd index 'til the end" (so index 3, 4, etc.).
Both return lists; in python, if you add lists, concatenation actually happens.
As an example, if old_list = [1,2,3,4,5], then new_list[:2] will be [1,2] and new_list[3:] will be [4,5]. So combining that will be [1,2,4,5].
Notice that this statement: v[2]==v[1] and v[1]==v[0] won't assign values!
Operation == return boolean.
Lets say your v looks like this: v = [1, 1, 3].
Then v[2]==v[1] and v[1]==v[0] gives you result: False and True, and this gives you reulst False. You can check it if you print this print(v[2]==v[1] and v[1]==v[0]).
If you want to assign values, you can use a statement like this: v[2], v[1] = v[1], v[0].
def main():
big_list = [ x for x in range(20) ]
while len(big_list) > 3:
big_list = big_list[:2] + big_list[3:]
print(big_list)

python - how to reassign element in array with for loop

I have a numpy array of floats that I want to reassign with a different value using a for loop but PyCharm says the new variable assignment isn't being used.
If I have, say:
for i in array:
i = i * 5
It will say that i is an unused variable. What am I doing wrong?
You need to assign values to array elements. Otherwise you array will remain unchanged. There are a couple of ways.
Using your current attempt as a starting point, you can use enumerate. Given an input array:
for idx, val in enumerate(array):
array[idx] = val * 5
But this doesn't take advantage of NumPy vectorisation. You can simply use:
array *= 5
Should be:
for i in range(len(array)):
array[i] = array[i] * 5
What you did was creating a temporary variable "i", which exists only on each loop iteration, it is initialized with the value of an element from the list and then it's deleted.
A more pythonic way of doing this would be:
array = [i*5 for i in array]

Looping through a list not in order in Python

I am very new to programming, so please bear with me...I have been learning Python and I just did an assessment that involved looping through a list using your current value as the next index value to go to while looping. This is roughly what the question was:
You have a zero-indexed array length N of positive and negative integers. Write a function that loops through the list, creates a new list, and returns the length of the new list. While looping through the list, you use your current value as the next index value to go to. It stops looping when A[i] = -1
For example:
A[0] = 1
A[1] = 4
A[2] = -1
A[3] = 3
A[4] = 2
This would create:
newlist = [1, 4, 2, -1]
len(newlist) = 4
It was timed and I was not able to finish, but this is what I came up with. Any criticism is appreciated. Like I said I am new and trying to learn. In the meantime, I will keep looking. Thanks in advance!
def sol(A):
i = 0
newlist = []
for A[i] in range(len(A)):
e = A[i]
newlist.append(e)
i == e
if A[i] == -1:
return len(newlist)
This might be the easiest way to do it if your looking for the least lines of code to write.
A = [1,4,-1,3,2]
B = []
n = 0
while A[n] != -1:
B.append(A[n])
n = A[n]
B.append(-1)
print(len(B))
First of all, note that for A[i] in range(len(A)) is a pattern you certainly want to avoid, as it is an obscure construct that will modify the list A by storing increasing integers into A[i]. To loop over elements of A, use for val in A. To loop over indices into A, use for ind in xrange(len(A)).
The for loop, normally the preferred Python looping construct, is not the right tool for this problem because the problem requires iterating over the sequence in an unpredictable order mandated by the contents of the sequence. For this, you need to use the more general while loop and manage the list index yourself. Here is an example:
def extract(l):
newlist = []
ind = 0
while l[ind] != -1:
newlist.append(l[ind])
ind = l[ind]
newlist.append(-1) # the problem requires the trailing -1
print newlist # for debugging
return len(newlist)
>>> extract([1, 4, -1, 3, 2])
[1, 4, 2, -1]
4
Note that collecting the values into the new list doesn't really make sense in any kind of real-world scenario because the list is not visible outside the function in any way. A more sensible implementation would simply increment a counter in each loop pass and return the value of the counter. But since the problem explicitly requests maintaining the list, code like the above will have to do.
It's simpler to just use a while loop:
data = [1,4,-1,3,2]
ls = []
i = 0
steps = 0
while data[i] != -1:
ls.append(data[i])
i = data[i]
steps += 1
assert steps < len(data), "Infinite loop detected"
ls.append(-1)
print ls, len(ls)

Categories

Resources