Bug In Using Del To Remove Elements In 2D List - python

So this is part of a bigger dataset but I simplified it here. Say You have the following code. What I'm trying to do is extract the sub arrays, based on what the middle element is (that's what dataStore is for). Side note, I know about list mutability and that when I do del row[1], I permanently affect data
dataStore = []
data = [[1,3,7], [1,0,1],[2,0,2],[9,0,9], [3,1,9]]
print(data)
for index in range(0, 5):
temp = []
for row in data:
if row[1] == index:
del row[1]
temp.append(row)
del data[ data.index(row)]
dataStore.append(temp)
The output is:
Data: [[2, 0, 2]]
DataStore: [[[1, 1], [9, 9]], [[3, 9]], [], [[1, 7]], []]
Now Data is supposed to be empty after I'm done, and the bug here is that (2,0,2) that doesn't get deleted because it's back to back with something that just got deleted. How do you get around this?
How I go about things: I feel like the reason is because when you do del data[ data.index(row)]it moves everything up by one but row is still iterating forward. So I was thinking of a solution of a 2nd mirror list but I couldn't figure out the syntax for it

Do you NEED the data array to be empty when you're done? I'm not sure, but maybe this is what you're looking for:
data = [[1,3,7], [1,0,1], [2,0,2], [9,0,9], [3,1,9]]
dataStore = []
for index in range(0, 5):
for row in data:
if row[1] == index:
dataStore.append([row[0], row[2]])
print(dataStore)
Everything is just stored in the new dataStore array instead of deleting the current data array. If you're iterating over an array, you never want to modify it while doing so. The output should be: [[1, 1], [2, 2], [9, 9], [3, 9], [1, 7]]
Note that this isn't the most efficient way to do this, but you won't notice unless you're working with very large sets of data.

Your feelings are correct. As a rule of thumb you should never modify a list if you are iterating through it.
If I understand your problem correctly, the end result of your code is that you should have an array in DataStore that is every element in data sorted by the middle element with the middle element removed. If that is the case then I would try something a little simpler like so:
dataStore = [[x[0],x[1]] for x in sorted(data,key=lambda i: i[1])]
del data

Related

Copy xarray into larger xarray in python?

I have an xarray of shape [3,] that looks like this
data= [2,4,6]
and I'm trying to copy it into array so that it looks like this:
data= [[2,4,6],[2,4,6],[2,4,6]]
(ie the entire array is copied three times).
I've tried a few different methods but keep getting:
data= [2 2 2,4 4 4,6 6 6]
Anyone know how I should go about doing this? (Also, sorry if I wrote this not according to the stack overflow rules, this is my first question...)
The first two answers don't actually copy the original array/list. Rather, they both just reference the array three times inside a new list. If you change one of the values inside of the the original array or any of the "copies" inside the new list, all of the "copies" of the array will change because they're really all the same structure just referenced in multiple places.
If you want to create a list containing three unique copies of your original array (xarray or list), you can do this:
new_list = [data[:] for _ in range(3)]
or if you want a new xarray containing your original array:
new_array = xarray.DataArray([data[:] for _ in range(3)])
I think the safest approach would be this:
import itertools
data = [2,4,6]
res = list(itertools.chain.from_iterable(itertools.repeat(x, 3) for x in [data]))
print(res)
Output: [[2, 4, 6], [2, 4, 6], [2, 4, 6]]

trying to replace similar items in a list with a character

I have rar file that contains some data, and I want to make a directory structure out of that and save it in an excel file. I used rarfile library to read the data, but it prints the data out like this
Resources/Custom Brushes/ClothDamageVDM.ZBP, 55.02MB
Resources/Custom Brushes/ControledGravityFolds.ZBP, 0.14MB
Resources/Custom Brushes/GeoStitches.ZBP, 0.06MB
Resources/Custom Brushes/LeatherTexturer.ZBP, 0.23MB
Resources/Custom Brushes/MagicFolds_Hard.ZBP, 5.89MB
Resources/Custom Brushes/MagicFolds_Soft.ZBP, 5.89MB
Resources/Custom Brushes/PreasureSizeFolds.ZBP, 0.07MB
Resources/Custom Brushes/VDM-folds.ZBP, 9.41MB
Resources/Custom Brushes/WovenNanoBrush.ZBP, 0.05MB
Resources/Custom Brushes/Wrinkles_Wrap.ZBP, 0.75MB
Resources/Custom Brushes/Xfolds.ZBP, 0.52MB
Resources/Hotkeys.TXT, 0.0MB
Resources/Masking Alphas/Masking Fold Alpha 01.jpg, 0.29MB
I would like to replace the similar items in these lines with a comma so it is nicely arranged in the excel sheet.
I managed to turn these lines to a list of lists, each list contains the content of the lines separated by the /, now I would like to replace the repeated items with commas, and here is the problem i have encountered.
i wrote the following code to generate a new list populated with commas
original_list= [[1,2,1],[1,2,3],[1,3],[1,3,5]]
# copy a new list
new_list = original_list[:]
for i in range(1, len(new_list)):
# adding the second item in the original list to a set a
a = set(original_list[i])
# adding the first item in the original list to a set b
b = set(original_list[i-1])
# getting the similar items between them in set c
c = list(a.intersection(b))
# for the length of the similar items, go through the new list and change similar items into a ,
for d in range (0, len(c)):
new_list[i][d] = ','
print(original_list)
print(new_list)
#both list are changed
but when I change the new list, the original changes as well. I don't know why when the new list is not a reference, I have used [:] to make sure it is a new list.
I'm quite sure there is a better method to what I am doing overall, so i would appreciate it if you guys can point me in the right direction. right now, I'm stuck at this.
thanks
The copying issue you are having is because you have nested lists, so list[:] doesn't go "deep enough". Check out this solution.
If you don't want to use a library, and you only need to copy on level deep, here is an example of a "brute force" "deep copy" using list comprehension to build a new list. This could be updated using recursion to copy multiple levels if needed, but you get the idea.
a = [[1, 2, 3], 9]
b = a[:]
b[0].append(4)
print(a)
print(b)
new = [x[:] if isinstance(x, list) else x for x in a]
new[0].append(5)
print()
print(a)
print(new)
[[1, 2, 3, 4], 9]
[[1, 2, 3, 4], 9]
[[1, 2, 3, 4], 9]
[[1, 2, 3, 4, 5], 9]
If you are looking for a code review, then Code Review is the more appropriate place to ask your question once your code is working. Stack Overflow is more intended for code that is not working.

Separating array elements from each other

I'm trying to separate every continuous segment of consecutive numbers in a different array.
For example,
# Input
x=[1,2,3,4,5,8,11,12,13,18]
# Output:
x=[[1,2,3,4,5],[8],[11,12,13],[18]]
The existing code,
x=[1,2,3,4,5,8,11,12,13,18]
temp=[]
firstnumber=0
for i in range(1,len(x)-1,1):
current=x[i]
previous=x[i-1]
if ((current-previous)!=1):
mm=(x[firstnumber:i-1])
temp.append(mm)
firstnumber=x[i]
print(temp)
I only got [[1, 2, 3, 4], []] as a result and I can't figure out why.
I have tried to answer this question changing as little of your code as possible.
x=[1,2,3,4,5,8,11,12,13,18]
temp=[]
firstnumber=0
first_index = 0
for i in range(1, len(x)):
current=x[i]
previous=x[i-1]
if ((current-previous)!=1):
mm = x[first_index:i]
temp.append(mm)
firstnumber = x[i]
first_index = i
temp.append(x[first_index:])
print(temp) # [[1, 2, 3, 4, 5], [8], [11, 12, 13], [18]]
What I changed:
firstnumber is being used as an index, but in reality is an element of the list, so we need to use first_index = i, the current index on that iteration.
The loop did not cover all the elements of the list, we need to go all the way to the end of the list so we iterate over range(1, len(x)
Finally even if the loop completes it will be missing the last sequence unless we add it after the loop, hence the addition of temp.append(x[first_index:])
NOTE: This method will work with the input you have but it not robust for all cases, nor is it the most efficient way to do this, however, your question was why it did not work as is so hopefully this answers that.
My answer does not intend to provide repaired code, but rather doing described task.
Note that you might use -1 index meaning last element. I would do it following way
x=[1,2,3,4,5,8,11,12,13,18]
temp=[x[:1]]
for i in x[1:]:
if temp[-1][-1]+1!=i: temp.append([])
temp[-1].append(i)
print(temp)
Output:
[[1, 2, 3, 4, 5], [8], [11, 12, 13], [18]]
Explanation: I firstly load first element as one-element list, then for following elements, if there is difference other than 1 between current and last-seen element then I append new empty list to temp, then independently from full-filling or not condition I add current element to last sublist.
x=[1,2,3,4,5,8,11,12,13,18]
x.append(x[-1]-2)
temp=[]
firstnumber=0
for i in range(1, len(x)):
current=x[i]
previous=x[i-1]
if ((current-previous)!=1):
mm=(x[firstnumber:i])
temp.append(mm)
firstnumber=i
print(temp)
In the code, the variable firstnumber is, I believe, supposed to contain the index of the first element of any continuous segment of consecutive numbers.
However, when you do firstnumber=x[i] that purpose is lost. Instead you can do, firstnumber = i and then it will work.
Also, this implementation will not append the last consecutive segment. As a result, you will have to do that outside the loop.

Restricting a Change to Only 1 List

I have nested lists (ie. [[list1],[list2]] and I want to make a change to only the first list.
My function is given as below:
function_name(data, list_number, change)
should return a change to only the list_number provided in the data
So my overall question is, how do I restrict this change to only the list_number given? If this is unclear please feel free to ask and clarify.
Ex:
Where the 'change' is already known which index it is going to replace, in this case it's going to replace the 2nd index of the first list (ie. 2)
data = [[1,2,3],[4,5,6]]
function_name(data, 1, 6)
data = [[1,6,3],[4,5,6]]
I have no idea where to even begin as the index is 'unknown' (ie. given by the user when the function is called)
List items are referenced via their index and nested lists can work the same way.
If your list were:
list = [['nest1_1', 'nest1_2']['nest2_1', 'nest2_2']]
You could change it in the following ways:
list[0] = ['nesta_1', 'nesta_2']
list[1][0] = 'second_1'
This would make your list now be:
[['nesta_1', 'nesta_2']['second_1', 'nest2_2']]
Try this code:
data = [[1,2,3],[4,5,6]]
def element_change(data, index_list, element_to_change, change):
a =''.join([ str(i) for i in data[index_list]])
data[index_list][a.find(str(element_to_change))] = change
return data
print(element_change(data, 0, 2, 6))
Input:
[[1, 2, 3], [4, 5, 6]]
Output:
[[1, 6, 3], [4, 5, 6]]
Simply what it does is casting list to string and merging them in order to be able to use find() method to find the index.

Appending value into list without duplicates

I have a list of integers containing:
intlist = [19,4,2,4]
and i want to append the value from the intlist into a list of list such that:
noDuplist = [[19,0],[4,1],[2,2]]
where the first index represents the value from the intlist and the second index represents the index of the value in the intlist. 19 is at index 0, 4 is at index 1 and 2 is at index 2. Since there is another 4 i do not want to include that since i didn't want duplicate hence the last 4 is just going to be left out.
I tried something like:
noDuplist = []
for i in range(len(intlist)):
if intlist[i] not in noDuplist:
noDuplist.append([intlist[i],i])
but I'm still getting
[[19, 0], [4, 1], [2, 2], [4, 3]]
where the [4,3] shouldnt be there. Would appreciate some help on this
I assume you want to retain the indices from the original sequence.
Thus what you want is something that remembers at what index was the value
first seen in the original sequence.
The problem is in your condition since
if intlist[i] not in noDuplist:
# something
would check if 4 was present in [[19, 0], [4, 1], [2, 2]]] which it isn't.
A cleaner way of doing this could be using dictionaries or sets.:
intlist = [19,4,2,4]
seen_so_far, noDuplist = set(), []
for i, v in enumerate(intlist):
if v not in seen_so_far:
noDuplist.append([v, i])
seen_so_far.add(v)
print(noDuplist)
Which gives the output [[19, 0], [4, 1], [2, 2]]
The first thing I'd suggest is not bothering storing the index as well as the value. You'll know the index when extracting elements anyway.
The first approach that comes to my mind (not sure if it's optimal) involves using a dictionary in combination with your list. Whenever you try to insert a value, check if it exists in your dictionary. If it doesn't, add it to the dictionary and your list. If it does, don't add it.
This would result in O(N) complexity.
Edit:
I didn't read your description thoroughly enough. Since you need the index from the original array, simply enter both as a key/value pair into your dictionary instead.

Categories

Resources