Im having difficulty utilizing an array in python - python

I'm trying to manipulate text from a word file however when I save it to an array of classes, all the indexes are being overwritten instead of the one particular index I intend to change.
for line in modified:
if line.startswith('Date'):
output.append(line)
list2=line.split(' ')
work.date=list2[1]
# print(work.date)
if line.startswith('PPV'): #list1[2]=l,[3]=t,[4]=v
output.append(line)
list1=line.split(' ')
work.lpv=list1[2]
# print("l is ",list1[2],work.lpv)
work.tpv=list1[3]
# print("t is ",list1[3],work.tpv)
work.vpv=list1[4]
# print("v is ",list1[4],work.vpv)
daylist[count]=work
#print("l2 is ",list1[2],work.lpv)
#print("daylist", count, "saved")
print(count,daylist[count].date) #this displays the correct value at the propper index but all other indexs have also been changed to this value
count+=1
Im trying to save a class which holds a string and a few floats to an array but cannot seem to get it to save to each index properly as it is read from the file. ive tried messing with the scope and list initialization but cant seem to figure it out. Any input would be appreciated, Thanks!

Every index in the daylist array references the same work object. When you change an attribute of work (e.g. work.date) it's reflected in all references to that single object. You want each index to reference a separate, independent object but that's not what the code is doing.
Try something like this where work is a dictionary:
for line in modified:
work = {} # <-- this makes the name "work" refer to a new, empty dict
if line.startswith('Date'):
output.append(line)
list2=line.split(' ')
work["date"] = list2[1]
elif line.startswith('PPV'):
output.append(line)
list1=line.split(' ')
work["lpv"] = list1[2]
# ...
print(count, daylist[count]["date"])
count += 1
Here's a helpful link on how names reference objects: How does Python referencing work?

Related

a bunch of user inputs (like a recipe), how can I skip to a line?

I'm writing a code as a "checklist" for something that is to be made.
each line is basically:
a0=int(input(f'do step one, then enter 1 to cont')
a1=int(input(f'do step two, then enter 1 to cont')
So, how can I skip to line a4 (or a(n) ) and continue from there?
My thoughts were to define each line and store each variable in a list. Then use a while loop to start from wherever. I just can't figure out how to eh, this is where I lose it. I guess I'm trying to convert the string to a variable name, to define it from there. See below:
ail=len(ai) #where ai=[a0,a1,a2..]
a=0 #i would input a as any val.
while a in range (0,ail):
b=(f'a{a}') #this line would determine the "instruction line" to start from.
exec("%s = %d" % (b,b)) #this is the line that names a var from a string
b0=int(input(f'{b}'))
I suggest you use dictionary instead of list. you can access the elements of dictionary using keys and that is going to help you pick a specific spot to traverse from.
Dictionary keys

dictionary being replaced and I am not sure why it is happening?

I have some code which is something along the lines of
storage = {}
for index, n in enumerate(dates):
if n in specific_dates:
for i in a_list:
my_dict[i] = {}
my_dict[i]["somthing"] = value
my_dict[i]["somthing2"] = value_2
else:
#print(storage[dates[index - 1]["my_dict"][i]["somthing"])
for i in a_list:
my_dict[i] = {}
my_dict[i][somthing] = different_value - storage[dates[index - 1]["my_dict"][i]["somthing"]
my_dict[i]["somthing2"] = different_value_2
storage[n]["my_dict"] = my_dict
The first pass will initiate the code in if n in specific_dates: the second pass goes to for i in a_list:
Essentially the code is getting a value set on specific dates and this value is then used for nonspecific dates that occur after the specific date until the next specific date overrides that value. However, at every date, i save a dictionary of values within a master dictionary called storage.
I found the problem which is when I print my_dict on the second pass my_dict[i] is literally an empty dictionary whereas prior to that loop it was filled. Where I have put the commented-out print line it would print value. I have fixed this by changing storage[n]["my_dict"] = my_dict to storage[n]["my_dict"] = my_dict.copy() and can now access value.
However, I do not really understand why this didnt work how I expected in the first place as I thought by assigning my_dict to storage it was creating new memory.
I was hoping someone could explain why this is happening and why storage[dates[index - 1]["my_dict"][i]["somthing"] doesn't create a new space in memory if that is indeed what is happening.

Appending item to list in Python overwring all existing elements

I am writing a script to read a .osu file and convert it to specific objects. This has to be done multiple times for each "hitobject"
The reading part works fine, however appending the object is the problem
When appending the object, it seems to overwrite all existing elements in the list. I can not for the life of me figure out why this is happening.
I have tried creating a "temp" list, which stores the objects in a local list instead of the "self.notes" list, still the same issue.
I believe the error is occurring in this part of the file:
if hitobjline != -1:
hitobjects = self.file_lines[hitobjline+1:]
for i in hitobjects:
ln = i[:i.find(':')].split(',')
new_note = [NoteType.Circle, NoteType.Hold][int(ln[3] == '128')]
add_note = File.Note
add_note.NoteTypeByte = ln[3]
add_note.Note_Number = int(ln[0])
add_note.Time = int(ln[2])
add_note.NoteType = new_note
add_note.Raw = ln
self.notes.append(add_note)
print(ln, ln[3], ln[3] == '128', new_note, add_note.NoteType)
For background, the .osu files have a syntax like: x,y,time,type,hit,end:stuff-i-dont-need-to-worry-about
I expected an out put of self.notes[0].NoteType to be osureader.NoteType.Hold as the first line of the file is 192,192,410,128,0,2974:0:0:0:0: (the 128 indicating the 'Hold'
However, I get, osureader.NoteType.Circle, the last line of the file.

Python text file searching for values and compiling results found

I have a large text file of lots of experimental results to search through for specific pieces of data, which I need to compile. The text file has results from many different experiments, and I need to keep the data from each experiment together.
e.g. (Not the actual data)
Object 1
The colour of the object is blue.
The size of the object is 0.5 m^3
The mass of the object is 0.8 g
Object 2
The colour of the object is pink.
The size of the object is 0.3m^3
etc.
I know where the values I want will be, as I can search the text for a specific phrase that I know will be present on the line the data is on.
One way I thought of doing it would be to search through the file for each specific line (I'm looking for two different variables), and add the value needed to a list. From this I would then create a dictionary for each object, assuming that at the same number in each list will be data from the same object.
e.g.
variable_one = []
variable_two = []
def get_data(file):
with open("filename.txt", "r") as file:
for line in file:
if "The colour" in line:
variable_one.append(line.split()[6])
if "The mass" in line:
variable_two.append(line.split()[6])
file.close()
or, to search through the file and create a list, with each entry being the section of data from a different object, then searching for the two variables for each object from within the different items in the list - again eventually storing the values from each object in a dictionary.
What I want to know is if there is a more efficient/better method for doing this than the ideas I had?
Here is an alternative which uses only one list and uses less "append" and less "in" and thus should be more effective.
variables = []
with open('filename.txt') as input:
colour = mass = ''
for line in input:
fields = line.split()
if len(fields)>6:
value = fields[6]
if 'The colour' in line:
colour = value
elif 'The mass' in line:
mass = value
elif line.startswith('Object'):
variables.append((colour, mass))
colour = mass = '' # may not be needed.
del(variables[0])
The way you are doing it there looks fine to me in general, except for the areas I mentioned in the comments, and the indexing causing an error if you have a line shorter than 6 words.

Python: problem with list append

Here is my code -
cumulative_nodes_found_list = []
cumulative_nodes_found_total_list = []
no_of_runs = 10
count = 0
while count < no_of_runs:
#My program code
print 'cumulative_nodes_found_list - ' + str(cumulative_nodes_found_list)
cumulative_nodes_found_total_list.insert(count,cumulative_nodes_found_list)
print 'cumulative_nodes_found_total_list - ' + str(cumulative_nodes_found_total_list)
count = count + 1
Here is a part of the output -
#count = 0
cumulative_nodes_found_list - [0.0, 0.4693999, 0.6482, 0.6927999999, 0.7208999999, 0.7561999999, 0.783399999, 0.813999999, 0.8300999999, 0.8498, 0.8621999999]
cumulative_nodes_found_total_list - [[0.0, 0.4693999, 0.6482, 0.6927999999, 0.7208999999, 0.7561999999, 0.783399999, 0.813999999, 0.8300999999, 0.8498, 0.8621999999]]
#count = 1
cumulative_nodes_found_list - [0.0, 0.55979999999999996, 0.66220000000000001, 0.69479999999999997, 0.72040000000000004, 0.75380000000000003, 0.77629999999999999, 0.79679999999999995, 0.82979999999999998, 0.84850000000000003, 0.85760000000000003]
cumulative_nodes_found_total_list -[[0.0, 0.55979999999999996, 0.66220000000000001, 0.69479999999999997, 0.72040000000000004, 0.75380000000000003, 0.77629999999999999, 0.79679999999999995, 0.82979999999999998, 0.84850000000000003, 0.85760000000000003],
[0.0, 0.55979999999999996, 0.66220000000000001, 0.69479999999999997, 0.72040000000000004, 0.75380000000000003, 0.77629999999999999, 0.79679999999999995, 0.82979999999999998, 0.84850000000000003, 0.85760000000000003]]
As the new item is appended the old item is replaced by new item. This trend continues.
Can anyone tell me why this is happening. I have tried using 'append' in place of insert but got the same output. However when I use 'extend' I get the correct output but I need inner items as lists which I dont get with extend.
You need to rebind cumulative_nodes_found_list at the beginning of the loop, instead of just clearing it.
This is psychic debugging at its best, since you're effectively asking "what is wrong with my code, which I'm not going to show to you".
All I can do is assume.
I'm assuming you're re-using the array objects in memory.
In other words, you do something like this:
list1.insert(0, list2)
list2.clear()
list2.append(10)
list2.append(15)
list1.insert(0, list2)
Since list1 points to the same array/list the whole time, and you're adding a reference to the object, and not a copy of it, later changes will make it appear your copy changed.
In other words, the result of the code above is going to be:
[[10, 15], [10, 15]]
regardless of what was in the list before you added it the first time.
Try assigning the changing list a new, empty, object each time you enter the loop body and see if that fixes anything.
You are adding a reference to cumulative_nodes_found_list to the cumulative_nodes_found_total_list, but it's the same reference each time. Move this line into the loop body:
cumulative_nodes_found_list = []
Lists are mutable objects. You're mutating cumulative_nodes_found_list inside your code, so the object added to your total list in the previous run is also mutated, because they are the same object.
Either make a copy to insert in the total:
for count in xrange(no_of_runs):
# ...
cumulative_nodes_found_total_list.append(list(cumulative_nodes_found_list))
... or reset the list on each iteration:
for count in xrange(no_of_runs):
cumulative_nodes_found_list = [] # creates a NEW list for this iteration
# ...
cumulative_nodes_found_total_list.append(cumulative_nodes_found_list)
I believe the problem is in the rest of your program code.
The items in cummulative_nodes_found_list is being replaced in-place each time through the loop.
I assume you're doing something like this:
while count < no_of_runs:
cummulative_nodes_found_list.clear()
#fill up the list with values using whatever program logic you have
cummulative_nodes_found_list.append(1.1)
cummulative_nodes_found_list.append(2.1)
print 'cumulative_nodes_found_list - ' + str(cumulative_nodes_found_list)
cumulative_nodes_found_total_list.insert(count,cumulative_nodes_found_list)
print 'cumulative_nodes_found_total_list - ' + str(cumulative_nodes_found_total_list)
count = count + 1
if this is, infact, what you're doing, then instead of using 'clear()' to clear the list, create a new one:
ie, replace cummulative_nodes_found_list.clear() with
cummulative_nodes_found_list = []
My guess is that you are not assigning the cumulative_nodes_found_list to be a new list each time, but updating its contents instead. So each time around the loop you are adding the same list reference to the total list. Since the reference within the totals list is the same object, when you update this list the next time around the loop, it affects what you hoped was the last loops values.
If you want to append to a list, use mylist.append(item) instead.
Also, if you iterate a fixed number of times it's better to use a for loop:
for i in range(no_of_runs):
# do stuff
The idea is, that range(no_of_runs) generates the list [0, 1, 2, ..., 10] for no_of_runs = 10 and the loop then iterates over its values.
Edit: this doesn't solve the problem. Other answers in this thread do, however. It's just a comment on style.
This method worked for me. Just like you, I was trying to append/insert a list into another list.
cumulative_nodes_found_total_list.insert(count,cumulative_nodes_found_list)
But the old values were being appended by the new values. So instead I tried this -
cumulative_nodes_found_total_list.insert(count,cumulative_nodes_found_list[:])
"Assignment statements in Python do not copy objects, they create
bindings between a target and an object."
Use deepcopy (or copy)

Categories

Resources