Replacing elements in arbitrary nested lists - python-3.x

I have an arbitrary data set, given in the form of nested lists. I wish to replace all values in my data > 0 with 1, to create a sort of binary array. Similar to normalizing.
I'm imagining this is best done with a for loop. I tried using enumerate but got confused working with enumerate types.
For example:
test = [[5,5,0,0,5],[0,0,0,0,5]]
for i in range(len(test)):
for j in range(len(test[i])):
if j > 0:
test[i][j] = 1
I'd expect:
[[1,1,0,0,1],[0,0,0,0,1]]
but instead got:
[[5, 1, 1, 1, 1], [0, 1, 1, 1, 1]]
Any help would be appreciated.

Since you need the values > 0 to be replaced, the condition should be as follows. Checking j > 0 would mean all nested list values except the first one would be set to 1.
test = [[5,5,0,0,5],[0,0,0,0,5]]
for i in range(len(test)):
for j in range(len(test[i])):
if test[i][j] > 0:
test[i][j] = 1

Related

Why does the insert function produce this result?

my_list = [1, 2]
for v in range(2):
my_list.insert(-1, my_list[v])
print(my_list)
The Result specifies 1, 1, 1, 2. Why isn't the result 1, 1, 2, 2 since v in the for loop would be 0 = 1 and 1 = 2?
list.insert(index, val) determines the index of the element before which to insert.
So in your first iteration you insert a value between the 1 and the 2.
Your new list looks like [1,1,2].
In the next iteration you operate on the changed list, thus you use the newly inserted 1, which is at v=1 now. Thus your list looks like
[1,1,1,2]
^ 1 2 ^
Here ^ are the original values and 1 and 2 are the iterations the values are added.

Getting rid of duplicates from a pair of corresponding lists

This is a program that I recently made. The goal of this code is to a pair of corresponding lists. So randomStringpt1[0] corresponds to randomStringpt2[0]. I want to compare randomStringpt1[0] and randomString2[0] to the rest of the pairs that the user gave in the randomStrings. But after using this code, it looks like I have duplicated each pair many times, which is the opposite of what I was looking for. I was thinking of using a dictionary, but then realized that a dictionary key could only have one value, which wouldn't help my case if the user used a number twice. Does anyone know how I can reduce the duplicates?
(The tests I have been running have been with the numbers randomStringpt1 = [1,3,1,1,3] and randomStringpy2 = [2,4,2,3,4]
)
randomStringpt1 = [1, 2, 3, 4, 5] #Pair of strings that correspond to each other("1,2,3,4,5" doesn't actually matter)
randomStringpt2 = [1, 2, 3, 4, 5]
for i in range(len(randomStringpt1)):
randomStringpt1[i] = input("Values for the first string: ")
randomStringpt2[i] = input("Corresponding value for the second string: ")
print(randomStringpt1) #numbers that the user chose for the first number of the pair
print(randomStringpt2) #numbers that the user chose for the second number of the pair
newStart = []
newEnd = []
for num1 in range(len(randomStringpt1)):
for num2 in range(len(randomStringpt1)):
if (int(randomStringpt1[num1]) != int(randomStringpt1[num2]) and int(randomStringpt2[num1]) != int(randomStringpt2[num2])):
newStart.append(randomStringpt1[num1]) # Adding the pairs that aren't equal to each other to a new list
newEnd.append(randomStringpt2[num1])
newStart.append(randomStringpt1[num2])
newEnd.append(randomStringpt2[num2])
# else:
# print("The set of numbers from the randomStrings of num1 are not equal to the ones in num2")
print(newStart)
print(newEnd)
First let's analyze the 2 bugs in your code,
the if condition inside the loop is true every time a pair compares to a different one. this means for your example it should output
[1, 1, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3]
[2, 2, 4, 4, 4, 2, 2, 3, 3, 4, 4, 4]
since you compare every pair to any other pair that exists. But your output is different because you append both pairs every time and getting a very big result, so you shouldn't append the num2 pairs.
Now, from what you described that you want, you should loop every pair and check if it already exists in the output list. So the for loop part can change like this
filtered = []
for pair in zip(randomStringpt1,randomStringpt2):
if pair not in filtered:
filtered.append(pair) # Adding the pairs that aren't equal to each other to a new list
the zip function takes the 2 lists and for every loop it returns 2 values one from each list the first value pair, then the second values and goes on. the filtered list will be in the following format [(1, 2), (3, 4), (1, 3)]
Alternative it can be as a one liner like this:
filtered = list(dict.fromkeys(zip(randomStringpt1, randomStringpt2)))
using the dictionary to identify unique elements and then turn it back into a list
after all that you can get the original format of the lists you had in your code by splitting them like this
newStart = [pair[0] for pair in filtered]
newEnd = [pair[1] for pair in filtered]
Finally i should tell you to read a little more on python and it's for loops, since the range(len(yourlist)) is not the python intended way to loop over lists, as python for loops are equivalent to for each loops on other languages and iterate over the list for you instead on relying in a value to get list elements like yourlist[value].

The best way of iterating through an array whose length changes in Python

I am implementing an algorithm which might affect the size of some array, and I need to iterate through the entire array. Basically a 'for x in arrayname' would not work because it does not update if the contents of arrayname are changed in the loop. I came up with an ugly solution which is shown in the following example:
test = np.array([1,2,3])
N = len(test)
ii=0
while ii < N:
N = len(test)
print(test[ii])
if test[ii] ==2:
test = np.append(test,4)
ii+=1
I am wondering whether a cleaner solution exists.
Thanks in advance!
Assuming all the elements are going to be added at the end and no elements are being deleted you could store the new elements in a separate list:
master_list = [1,2,3]
curr_elems = master_list
while len(curr_elems) > 0: # keep looping over new elements added
new_elems = []
for item in curr_elems: # loop over the current list of elements, initially the list but then all the added elements on second run etc
if should_add_element(item):
new_elems.append(generate_new_element(item))
master_list.extend(new_elems) # add all the new elements to our master list
curr_elems = new_elems # and prep to iterate over the new elements for next iteration of the while loop
The while loop seems the best solution. As the condition is re-evaluated at each iteration, you don’t need to reset the length of the list in the loop, you can do it inside the condition:
import random
l = [1, 2, 3, 4, 5]
i = 0
while i < len(l):
if random.choice([True, False]):
del l[i]
else:
i += 1
print(f'{l=}')
This example gives a blueprint for a more complex algorithm. Of course, in this simple case, it could be coded more simply with a filter, or like this:
l = [1, 2, 3, 4, 5]
[x for x in l if random.choice([True, False])]
You might want to check this related post for more creative solutions: How to remove items from a list while iterating?

How to pass an element in list as an index to a list in python?

Given a sorted list [1,2,3,4,5,6,7,8] and a shuffled version of that list
a=[1,2,5,3,7,8,6,4]
I want to find how many steps each element has moved from its position relative to the sorted list (steps towards index 0 being positive, steps away from index 0 being negative) and store those step values in the respective index in a different list.
For the given input, the expected output is:
b=[0,0,-1,-4,2,-1,2,2]
Considering the value 3 (which is at index 2 in the sorted list), in the shuffled array it is at index 3, so it has taken -1 step, and hence b[2] = -1. Similarly for the value 8 (which is at index 7 in the sorted list), in the shuffled array it is at index 5, so it has taken +2 steps, and hence b[7] = 2.
This is what I have tried:
b=[0,0,0,0,0,0,0,0]
a=[1,2,5,3,7,8,6,4]
for x in range(len(a)):
b[a[x]]=a[x]-(x+1)
I am getting an error with this code:
IndexError: list assignment index out of range
Please help me understand this. Why can't I pass an integer from a list as an index to another list?
You can get the result you want with a simple comparison of the expected value at an array position with the index of that value in the a array. By iterating over the number of elements in a, we can generate the output array:
a = [1,2,5,3,7,8,6,4]
b = []
for x in range(len(a)):
b.append(x - a.index(x+1))
print(b)
Output
[0, 0, -1, -4, 2, -1, 2, 2]
Demo on rextester
The problem as you very well know is that there is an index error.
a=[1,2,5,3,7,8,6,4]
The above array has size = 8.
Now you create b:
b=[0,0,0,0,0,0,0,0]
The size of the list b is also 8.
In your for loop you are doing:
b[a[x]]
Pause...
If x is 5, then a[x] will be 8. However, there is no such thing as index 8 in list b, which only has up to index 7.
This is the problem.
You should change the code in your for-loop to:
b[a[x] - 1]=a[x]-(x+1)
I would suggest you change your loop to this:
for x, n in enumerate(a):
b[n-1] = n-(x+1)
Index starts from 0 to n-1
,so in b=[0,0,0,0,0,0,0,0] (having 8 elements) index will start from 0 to 7 and list 'a=[1,2,5,3,7,8,6,4]' contains numbers from 1-8 hence 8 is out of index.
corrected code:
b=[0,0,0,0,0,0,0,0]
a=[1,2,5,3,7,8,6,4]
for x in range(len(a)):
b[a[x] - 1]=a[x]-(x + 1)
Avoiding any indexing, nor unnecessary offsets, we can store the elements in a dictionary (the element as the key and its move as the value)
a=[1,2,5,3,7,8,6,4]
d = {v: v-e for e,v in enumerate(a, 1)}
b = [v for _, v in sorted(d.items())]
print(b)
produces
[0, 0, -1, -4, 2, -1, 2, 2]

How can I call a previous element inside a loop in python

I am trying something like this-
for j in range(1,100):
ej=[]
rj=[]
vj=[]
for i in range(0,10):
pj=(r(j-1)[i]+v(j-1)[i]*0.01)
qj=v(j-1)[i]
rj.insert(i,pj)
vj.insert(i,qj)
for i in range(0,10):
z1=0.5*1*(vj[i]**2)
ej.insert(i,z1)
ejtotal=sum(ej)
print(j,ejtotal)
Where i want the j loop to start from 1, and I will give the value of r0 and v0 beforehand. But the part r(j-1), v(j-1) is not working, it cannot understand (j-1) and call the previous value of that object. Can anyone help? Thanks in advance.
It sounds like you have variables with numbers in them, such as r0 and v0, and you're trying to look them up using a numerical calculation r(j-1). This doesn't work, as Python interprets r(j-1) as an attempt to call a function r with the argument j-1. I suspect you'll also find that your rj, vj and ej values aren't doing what you expect (they're not writing to r1, v1, e1 and so on, they're just names that end with "j").
You should instead use a list for the r values, and append the new values for each j value. Instead of r0, you'd look up r[0]. There will be no issue if you use r[j-1].
I suspect you want something like:
r = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] # example r[0] data
v = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] # example v[0] data
e = [[]] # no e0 value is used
for j in range(1,100):
r.append([r[j-1][i]+v[j-1][i]*0.01 for i in range(10)])
v.append([v[j-1][i] for i in range(10)])
e.append([0.5*1*(v[j][i]**2) for i in range(10)])
ejtotal = sum(e[j])
print(j,ejtotal)
I've simplified things a bit by replacing the inner loops by list comprehensions. You could reduce it quite a bit more by using the index -1 to refer to the last item in a sequence, and perhaps iterating directly over the values in the preceeding list rather than indexing them. You could also just reuse the first v and e values, since they do not change with increasing j values.

Resources