I am trying to build an efficient function for splitting a list of any size by any given number of indices. This method works and it took me a few hours to get it right (I hate how easy it is to get things wrong when using indexes)
Am I over-thinking this?
Code:
def lindexsplit(List,*lindex):
index = list(lindex)
index.sort()
templist1 = []
templist2 = []
templist3 = []
breakcounter = 0
itemcounter = 0
finalcounter = 0
numberofbreaks = len(index)
totalitems = len(List)
lastindexval = index[(len(index)-1)]
finalcounttrigger = (totalitems-(lastindexval+1))
for item in List:
itemcounter += 1
indexofitem = itemcounter - 1
nextbreakindex = index[breakcounter]
#Less than the last cut
if breakcounter <= numberofbreaks:
if indexofitem < nextbreakindex:
templist1.append(item)
elif breakcounter < (numberofbreaks - 1):
templist1.append(item)
templist2.append(templist1)
templist1 = []
breakcounter +=1
else:
if indexofitem <= lastindexval and indexofitem <= totalitems:
templist1.append(item)
templist2.append(templist1)
templist1 = []
else:
if indexofitem >= lastindexval and indexofitem < totalitems + 1:
finalcounter += 1
templist3.append(item)
if finalcounter == finalcounttrigger:
templist2.append(templist3)
return templist2
Related
I am new to GLPK, so my apologies in advance if I'm missing something simple!
I have a largeish LP that I am feeding through GLPK to model an energy market. I'm running the following command line to GLPK to process this:
winglpk-4.65\glpk-4.65\w64\glpsol --lp problem.lp --data ExampleDataFile.dat --output results2.txt
When I open the resulting text file I can see the outputs, which all look sensible. I have one big problem: each record is split over two rows, making it very difficult to clean the file. See an extract below:
No. Row name St Activity Lower bound Upper bound Marginal
------ ------------ -- ------------- ------------- ------------- -------------
1 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1990)_
NS 0 0 = < eps
2 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1991)_
NS 0 0 = < eps
3 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1992)_
NS 0 0 = < eps
4 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1993)_
NS 0 0 = < eps
5 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1994)_
NS 0 0 = < eps
6 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1995)_
NS 0 0 = < eps
7 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1996)_
NS 0 0 = < eps
8 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1997)_
NS 0 0 = < eps
9 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1998)_
NS 0 0 = < eps
10 c_e_SpecifiedDemand(UTOPIA_CSV_ID_1999)_
NS 0 0 = < eps
11 c_e_SpecifiedDemand(UTOPIA_CSV_ID_2000)_
NS 0 0 = < eps
12 c_e_SpecifiedDemand(UTOPIA_CSV_ID_2001)_
NS 0 0 = < eps
13 c_e_SpecifiedDemand(UTOPIA_CSV_ID_2002)_
NS 0 0 = < eps
14 c_e_SpecifiedDemand(UTOPIA_CSV_ID_2003)_
NS 0 0 = < eps
15 c_e_SpecifiedDemand(UTOPIA_CSV_ID_2004)_
NS 0 0 = < eps
I would be very grateful of any suggestions for either:
How I can get each record in the output text file onto a single row, or
Ideas on how to clean / post-process the existing text file output.
I'm sure I'm missing something simple here, but the output is in a very unhelpful format at the moment!
Thanks!
I wrote a Python parser for the GLPK output file. It is not beautiful and not save (try-catch) but it is working (for pure simplex problems).
You can call it on output file:
outp = GLPKOutput('myoutputfile')
print(outp)
val1 = outp.getCol('mycolvar','Activity')
val2 = outp.getRow('myrowname','Upper_bound') # row names should be defined
The class is as follows:
class GLPKOutput:
def __init__(self,filename):
self.rows = {}
self.columns = {}
self.nRows = 0
self.nCols = 0
self.nNonZeros = 0
self.Status = ""
self.Objective = ""
self.rowHeaders = []
self.rowIdx = {}
self.rowWidth = []
self.Rows = []
self.hRows = {}
self.colHeaders = []
self.colIdx = {}
self.colWidth = []
self.Cols = []
self.hCols = {}
self.wcols = ['Activity','Lower_bound','Upper bound','Marginal']
self.readFile(filename)
# split columns with weird line break
def smartSplit(self,line,type,job):
ret = []
line = line.rstrip()
if type == 'ROWS':
cols = len(self.rowHeaders)
idx = self.rowWidth
else:
cols = len(self.colHeaders)
idx = self.colWidth
if job == 'full':
start = 0
for i in range(cols):
stop = start+idx[i]+1
ret.append(line[start:stop].strip())
start = stop
elif job == 'part1':
entries = line.split()
ret = entries[0:2]
elif job == 'part2':
start = 0
for i in range(cols):
stop = start+idx[i]+1
ret.append(line[start:stop].strip())
start = stop
ret = ret[2:]
# print()
# print("SMART:",job,line.strip())
# print(" TO:",ret)
return ret
def readFile(self,filename):
fp = open(filename,"r")
lines = fp.readlines()
fp.close
i = 0
pos = "HEAD"
while pos == 'HEAD' and i<len(lines):
entries = lines[i].split()
if len(entries)>0:
if entries[0] == 'Rows:':
self.nRows = int(entries[1])
elif entries[0] == 'Columns:':
self.nCols = int(entries[1])
elif entries[0] == 'Non-zeros:':
self.nNonZeros = int(entries[1])
elif entries[0] == 'Status:':
self.Status = entries[1]
elif entries[0] == 'Objective:':
self.Objective = float(entries[3]) #' '.join(entries[1:])
elif re.search('Row name',lines[i]):
lines[i] = lines[i].replace('Row name','Row_name')
lines[i] = lines[i].replace('Lower bound','Lower_bound')
lines[i] = lines[i].replace('Upper bound','Upper_bound')
entries = lines[i].split()
pos = 'ROWS'
self.rowHeaders = entries
else:
pass
i+= 1
# formatting of row width
self.rowWidth = lines[i].split()
for k in range(len(self.rowWidth)): self.rowWidth[k] = len(self.rowWidth[k])
# print("Row Widths:",self.rowWidth)
i+= 1
READY = False
FOUND = False
while pos == 'ROWS' and i<len(lines):
if re.match('^\s*[0-9]+',lines[i]): # new line
if len(lines[i].split())>2: # no linebrak
entries = self.smartSplit(lines[i],pos,'full')
READY = True
else: # line break
entries = self.smartSplit(lines[i],pos,'part1')
READY = False
FOUND = True
else:
if FOUND and not READY: # second part of line
entries += self.smartSplit(lines[i],pos,'part2')
READY = True
FOUND = False
if READY:
READY = False
FOUND = False
# print("ROW:",entries)
if re.match('[0-9]+',entries[0]): # valid line with solution data
self.Rows.append(entries)
self.hRows[entries[1]] = len(self.Rows)-1
else:
print("wrong line format ...")
print(entries)
sys.exit()
elif re.search('Column name',lines[i]):
lines[i] = lines[i].replace('Column name','Column_name')
lines[i] = lines[i].replace('Lower bound','Lower_bound')
lines[i] = lines[i].replace('Upper bound','Upper_bound')
entries = lines[i].split()
pos = 'COLS'
self.colHeaders = entries
else:
pass #print("NOTHING: ",lines[i])
i+= 1
# formatting of row width
self.colWidth = lines[i].split()
for k in range(len(self.colWidth)): self.colWidth[k] = len(self.colWidth[k])
# print("Col Widths:",self.colWidth)
i+= 1
READY = False
FOUND = False
while pos == 'COLS' and i<len(lines):
if re.match('^\s*[0-9]+',lines[i]): # new line
if len(lines[i].split())>2: # no linebreak
entries = self.smartSplit(lines[i],pos,'full')
READY = True
else: # linebreak
entries = self.smartSplit(lines[i],pos,'part1')
READY = False
FOUND = True
else:
if FOUND and not READY: # second part of line
entries += self.smartSplit(lines[i],pos,'part2')
READY = True
FOUND = False
if READY:
READY = False
FOUND = False
# print("COL:",entries)
if re.match('[0-9]+',entries[0]): # valid line with solution data
self.Cols.append(entries)
self.hCols[entries[1]] = len(self.Cols)-1
else:
print("wrong line format ...")
print(entries)
sys.exit()
elif re.search('Karush-Kuhn-Tucker',lines[i]):
pos = 'TAIL'
else:
pass #print("NOTHING: ",lines[i])
i+= 1
for i,e in enumerate(self.rowHeaders): self.rowIdx[e] = i
for i,e in enumerate(self.colHeaders): self.colIdx[e] = i
def getRow(self,name,attr):
if name in self.hRows:
if attr in self.rowIdx:
try:
val = float(self.Rows[self.hRows[name]][self.rowIdx[attr]])
except:
val = self.Rows[self.hRows[name]][self.rowIdx[attr]]
return val
else:
return -1
def getCol(self,name,attr):
if name in self.hCols:
if attr in self.colIdx:
try:
val = float(self.Cols[self.hCols[name]][self.colIdx[attr]])
except:
val = self.Cols[self.hCols[name]][self.colIdx[attr]]
return val
else:
print("key error:",name,"not known ...")
return -1
def __str__(self):
retString = '\n'+"="*80+'\nSOLUTION\n'
retString += "nRows: "+str(self.nRows)+'/'+str(len(self.Rows))+'\n'
retString += "nCols: "+str(self.nCols)+'/'+str(len(self.Cols))+'\n'
retString += "nNonZeros: "+str(self.nNonZeros)+'\n'
retString += "Status: "+str(self.Status)+'\n'
retString += "Objective: "+str(self.Objective)+'\n\n'
retString += ' '.join(self.rowHeaders)+'\n'
for r in self.Rows: retString += ' # '.join(r)+' #\n'
retString += '\n'
retString += ' '.join(self.colHeaders)+'\n'
for c in self.Cols: retString += ' # '.join(r)+' #\n'
return retString
I am having trouble storing the ID to keys, like a sub (parent-child) kind of thing. I spent hours on it and could not figure a way to accomplish this. What output I am expecting is at the end of this post. Any help would be great.
import sys
import collections
dict = collections.OrderedDict()
dict["A.1"] = {"parent_child":0}
dict["A.1.1"] = {"parent_child":1}
dict["A.1.1.1"] = {"parent_child":2}
dict["A.1.1.2"] = {"parent_child":2}
dict["A.1.1.3"] = {"parent_child":2}
dict["A.1.2"] = {"parent_child":1}
dict["A.1.2.1"] = {"parent_child":2}
dict["A.1.2.2"] = {"parent_child":2}
dict["A.1.2.2.1"] = {"parent_child":3}
dict["A.1.2.2.2"] = {"parent_child":3}
dict["A.1.2.3"] = {"parent_child":2}
dict["A.1.3"] = {"parent_child":1}
dict["A.1.4"] = {"parent_child":1}
print(dict)
new_dict = {}
p = 0 # previous index
i = 0 # current
n = 1 # next index
current_PC = 0 # current parent_child
next_PC = 0 # next parent_child
previous_id = ""
current_id = ""
next_id = ""
change_current = True
change = True
lst = []
while(True):
if change_current:
current_id = dict.keys()[i]
current_PC = dict.values()[i]["parent_child"]
change_current = False
try:
next_id = dict.keys()[n]
next_PC = dict.values()[n]["parent_child"]
except:
pass # it will go out of index
print("KEY {0}".format(current_id))
if next_PC > current_PC:
if next_PC - current_PC == 1:
lst.append(next_PC)
next_PC += 1
print("next_PC: {0}".format(next_PC))
if next_PC == current_PC:
new_dict[current_id] = lst
lst = []
break
print(new_dict)
Trying to make output looks like this (at in similar way), the new_dict should look like:
new_dict["A.1"] = ["A.1.1", "A.1.2", "A.1.3", "A.1.4"]
new_dict["A.1.1"] = ["A.1.1.1", "A.1.1.2", "A.1.1.3"]
new_dict["A.1.1.1"] = []
new_dict["A.1.1.2"] = []
new_dict["A.1.1.3"] = []
new_dict["A.1.2"] = ["A.1.2.1", "A.1.2.2", "A.1.2.3"]
new_dict["A.1.2.1"] = []
new_dict["A.1.2.2"] = ["A.1.2.2.1", "A.1.2.2.2"]
new_dict["A.1.2.2.1"] = []
new_dict["A.1.2.2.2"] = []
new_dict["A.1.2.3"] = []
new_dict["A.1.3"] = []
new_dict["A.1.4"] = []
This gives you the output you are asking for. Since i did not see a {"parent_child":...} in you desired output i did not proceed with anything else.
options = ["A.1","A.1.1","A.1.1.1","A.1.1.2","A.1.1.3","A.1.2","A.1.2.1","A.1.2.2","A.1.2.2.1","A.1.2.2.2","A.1.2.3","A.1.3","A.1.4"]
new_dict = {}
for i, key in enumerate(options):
new_dict[key] = []
ls = []
for j, opt in enumerate(options):
if (key in opt) and (len(opt)-len(key)==2):
new_dict[key].append(opt)
print(new_dict)
EDIT
Using the comment of #Ranbir Aulakh
options = ["A.1","A.1.1","A.1.1.1","A.1.1.2","A.1.1.3","A.1.2","A.1.2.1","A.1.2.2","A.1.2.2.1","A.1.2.2.2","A.1.2.3","A.1.3","A.1.4"]
new_dict = {}
for i, key in enumerate(options):
new_dict[key] = []
ls = []
for j, opt in enumerate(options):
if (key in opt) and (len(opt.split("."))-len(key.split("."))==1):#(len(opt)-len(key)==2):
new_dict[key].append(opt)
print(new_dict)
I'm trying to plot two files of data of this type:
name1.fits 0 0 2.40359218172
name2.fits 0 0 2.15961244263
The third column has values from 0 to 5. I want to plot column 2 vs column 4, but, for lines with values in col 3 less than 2 (0 and 1), I want to shift col 2 by -0.1, and for lines with values greater than 3 (4 and 5) I want to shift col 2 by +0.1.
However my code seems to be shifting all values by +0.1. Here is what I have so far:
import matplotlib.pyplot as plt
import numpy as np
with open('file1.txt') as data, open('file2.txt') as stds:
lines1 = data.readlines()
lines2 = stds.readlines()
x1a = []
x2a = []
x1b = []
x2b = []
x1c = []
x2c = []
y1a = []
y2a = []
y1b = []
y2b = []
y1c = []
y2c = []
for line1 in lines1:
p = line1.split()
if p[2] < 2:
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < p[2] < 4:
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif p[2] > 3:
x1c.append(float(p[1]))
y1c.append(float(p[3]))
for line2 in lines2:
q = line2.split()
if q[2] < 2:
x2a.append(float(q[1]))
y2a.append(float(q[3]))
elif 1 < q[2] < 4:
x2b.append(float(q[1]))
y2b.append(float(q[3]))
elif q[2] > 3:
x2c.append(float(q[1]))
y2c.append(float(q[3]))
x1a = np.array(x1a)
x2a = np.array(x2a)
x1b = np.array(x1b)
x2b = np.array(x2b)
x1c = np.array(x1c)
x2c = np.array(x2c)
y1a = np.array(y1a)
y2a = np.array(y2a)
y1b = np.array(y1b)
y2b = np.array(y2b)
y1c = np.array(y1c)
y2c = np.array(y2c)
minorLocator = AutoMinorLocator(5)
fig, ax = plt.subplots(figsize=(8, 8))
fig.subplots_adjust(left=0.11, right=0.95, top=0.94)
plt.plot(x1a-0.1,y1a,'b^',mec='blue',label=r'B0',ms=8)
plt.plot(x2a-0.1,y2a,'r^',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.plot(x1b,y1b,'bo',mec='blue',label=r'B0',ms=8)
plt.plot(x2b,y2b,'ro',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.plot(x1c+0.1,y1c,'bx',mec='blue',label=r'B0',ms=8)
plt.plot(x2c+0.1,y2c,'rx',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.axis([-1.0, 3.0, 0., 4])
ax.xaxis.set_tick_params(labeltop='on')
ax.yaxis.set_minor_locator(minorLocator)
plt.show()
Here is the plot:
plot
I'm pretty sure the problem is in my "ifs". I hope you can clear the way and/or show me a better option for this.
When you do your queries (if) you must ensure the conversion happens before the question so:
for line1 in lines1:
p = line1.split()
if p[2] < 2:
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < p[2] < 4:
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif p[2] > 3:
x1c.append(float(p[1]))
y1c.append(float(p[3]))
, should actually be:
for line1 in lines1:
p = line1.split()
if float(p[2]) < 2: # changed here
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < float(p[2]) < 4: # There seems to be a problem with this if
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif float(p[2]) > 3: # changed here
x1c.append(float(p[1]))
y1c.append(float(p[3]))
The same for your q variables. Also notice that asking 1 < x < 4 will intercept with x > 3 and x < 2. You should also correct this.
This is my first time coding. I'm doing it as ab elective module. I have to program an ai_player to go from playing randomly to winning and I'm stuck. Any advice would be appreciated. The game is Connect 4. i keep getting "object has no attribute" error.
import random
import time
def board():
for i in range(0, 8, 1):
for j in range(0, 10, 1):
board[i][j] = 0
return board
def move(board, valid_move):
start_time = time.time()
x = 0
while x == 0:
i = range(7, -1, -1)
j = range(0, 10, 1)
first_move = board[i][j]
board[7][4] = 1
if board[i-1][j] == 0: #above
first_move = [i, j]
x = 1
print " valid above"
return j
elif (board[i][j+1] == 0 and (i <= 7 and j <= 9)) or (board[i-1][j+1] == 0 and (i <= 7 and j <= 9)) or (board[i-1][j+1] == 0 and (i <= 7 and j <= 9)): #right
first_move = [i, (j+1)]
x = 1
print " valid right"
return (j+1)
elif board[i][j-1] == 0 or board[i-1][j-1] == 0 or board[i-1][j-1] == 0: #left
first_move = [i, (j-1)]
x = 1
print " valid left"
return (j-1)
else:
r = random.randint(0, 7)
c = random.randint(0, 9)
first_move = [r, c]
x = 1
print " random move"
return c
end_time = time.time() - start_time
print end_time
return first_move
File "F:/5. Fifth year/1st Semester/MPR 213 2016/Project 2016/attempts.py", line 20, in board
board[i][j] = 0
TypeError: 'function' object has no attribute '__getitem__'
It looks like you're trying to create a multidimensional list called board. This is not how you do that though, what you've actually done is created a function called board, and then you try to index that function, which fails since it's not a list.
To create board, use something like
board = [[0] * 10 for i in range(0, 8)]
I am trying to implement the merge sort algorithm using the following code but am getting a list index is out of range error.
def mergeSort (unSortedList):
if len(unSortedList) == 1 :
return unSortedList
else:
midpoint = len(unSortedList)//2
A = mergeSort (unSortedList[:midpoint] )
B = mergeSort (unSortedList[midpoint:] )
i = 0
j = 0
C = []
for k in range(len(unSortedList)):
if A[i] >= B[j]:
C.append(A[i])
if i == len(A):
C.append(B[j:])
else:
i += 1
elif A[i] < B[j] :
C.append(B[j])
if j == len(B):
C.append(A[i:])
else:
j += 1
return C
testlist = [2,1,4,2,5,6,8,9]
print (mergeSort(testlist))
Any help would be appreciated.
Here is my version of your mergeSort, with the merge function extracted:
def mergeSort (unSortedList):
if len(unSortedList) == 1 :
return unSortedList
else:
midpoint = len(unSortedList)//2
A = mergeSort (unSortedList[:midpoint] )
B = mergeSort (unSortedList[midpoint:] )
return merge(A, B)
def merge(a, b):
i = 0
j = 0
c = []
while True:
if a[i] < b[j]:
c.append(b[j])
j += 1
elif a[i] >= b[j]:
c.append(a[i])
i += 1
if i == len(a):
c.extend(b[j:])
break
if j == len(b):
c.extend(a[i:])
break
return c
Output:
>>> testlist = [2,1,4,2,5,6,8,9]
>>> mergeSort(testlist)
[9, 8, 6, 5, 4, 2, 2, 1]
Couple of things to note:
Appending a list to a list. When you do C.append(A[j:]) you end up with nested lists. That is because A[j:] always returns a list. You either need to use list addition - C += A[j:] - or call extend - C.extend(A[j:])
Missing breaks. When your i or j got to the end of their lists you correctly appended the rest of the other list but you did not terminate the loop. That is what caused the range error because in the next iteration (which should not happen) you tried to get an item at the index equal to the length of the list which is out of range.