When calling a recursive function to order the values, it skips one. How to fix it?
I have a recursive function that reads a list of scout records from a file and then adds them in order of their ID to the list. The function is called with addScouts(1)
. Function below:
def addScouts(self,I):
i = I
with open(fileName,"r") as f:
lines = f.readlines()
for line in lines:
if str(line.split(",")[3])[:-1] == str(i):
self.scoutList.insert(END,line[:-1])
i += 1
return self.addScouts(i)
return
My problem is that my file id is ordered 1,2,4,5
since at some point I deleted the scout with id 3. However, when I run the function to re-order the scouts in the list (function above) it only displays the scouts before and including the ID 3. This is because when i = 3
none of the items in the file are equal to 3, so the function reaches the end and returns before it can check the remaining entries.
File contents:
Kris,Rice,17,1 Olly,Fallows,17,2 Olivia,Bird,17,4 Louis,Martin,18,5
Any idea how to fix this?
source to share
Just select the last column:
sorted(f,key=lambda x: int(x.split(",")[-1]))
You can use bisect to find where to put the new data to keep the ordered data after sorting it once:
from bisect import bisect
import csv
with open("foo.txt") as f:
r = list(csv.reader(f))
keys = [int(row[-1]) for row in r]
new = ["foo","bar","12","3"]
ind = bisect(keys, int(new[-1]))
r.insert(ind,new)
print(r)
Output:
[['Kris', 'Rice', '17', '1'], ['Olly', 'Fallows', '17', '2'], ['foo', 'bar', '12', '3'], ['Olivia', 'Bird', '17', '4'], ['Louis', 'Martin', '18', '5']]
The simplest way to check the first line with a higher id, if none of them above, just add at the end:
import csv
with open("foo.txt") as f:
r = list(csv.reader(f))
new = ["foo","bar","12","3"]
key = int(new[-1])
ind = None
for i, row in enumerate(r):
if int(row[-1]) >= key:
ind = i
break
r.insert(ind, new) if ind is not None else r.append(new)
print(r)
Output:
[['Kris', 'Rice', '17', '1'], ['Olly', 'Fallows', '17', '2'], ['foo', 'bar', '12', '3'], ['Olivia', 'Bird', '17', '4'], ['Louis', 'Martin', '18', '5']
To always add this file in order when adding a new value, we just need to write to a temporary file, write the line to the correct location, and then replace the original with the updated file:
import csv
from tempfile import NamedTemporaryFile
from shutil import move
with open("foo.csv") as f, NamedTemporaryFile(dir=".", delete=False) as temp:
r = csv.reader(f)
wr = csv.writer(temp)
new = ["foo", "bar", "12", "3"]
key, ind = int(new[-1]), None
for i, row in enumerate(r):
if int(row[-1]) >= key:
wr.writerow(new)
wr.writerow(row)
wr.writerows(r)
break
wr.writerow(row)
else:
wr.writerow(new)
move(temp.name, "foo.csv")
foo.csv after the data is in order:
Kris,Rice,17,1 Olly,Fallows,17,2 foo,bar,12,3 Olivia,Bird,17,4 Louis,Martin,18,5
source to share
You can check if your list is the same length as your file, and if not, you run addScouts again, and if true, you end up. Like this:
def addScouts(self,I):
i = I
with open(fileName,"r") as f:
lines = f.readlines()
for line in lines:
if str(line.split(",")[3])[:-1] == str(i):
self.scoutList.insert(END,line[:-1])
i += 1
return self.addScouts(i)
if len(scoutList) < len(lines):
return self.addScouts(i+1)
else:
return
source to share