I have been learning about table constructors in Lua from http://www.lua.org/pil/3.6.html and I can't understand the difference between these two pieces of code.
--between code I've written--
list = nil
for line in io.lines() do
list = {value=line}
end
l = list
while l do
print(l.value)
end
--and between code they have written--
list = nil
for line in io.lines() do
list = {next=list, value=line}
end
l = list
while l do
print(l.value)
l = l.next
end
A linked list needs to have a way to get to the next value in the chain.
Without defining next in the table you have no next value, indexing value does not automatically move l to the next value in the list. By not defining next = list the last value of list is lost and your end result will be only a single value, the last value from your data source.
I changed this example so that is didn't need a file to work with:
Here your code will loop indefinitely printing f each and every time.
list = nil
for _,letter in ipairs({'a','b','c','d','e','f'}) do
list = {value=letter} -- we reassign list with new data without preserving the
-- previous data
end
l = list
while l do
print(l.value) -- the last value of list was {value = 'f'} and it will not
-- change in this loop
end
Where as the code from the example will go through each value given and complete.
list = nil -- this marks the end of the list and creates our name
-- we will use to store the list.
for _,letter in ipairs({'a','b','c','d','e','f'}) do
list = {next=list, value=letter} -- the first loop we will create a table where `next` is
-- nil.
-- on the second loop we create a table where `next` is
-- referencing the table from loop 1 that is stored in list.
-- this will repeat until we have gone through all the
-- letter from our source.
end
l = list
while l do
print(l.value) -- print our letter.
l = l.next -- move on to the table we stored in `next`.
-- this loop ends when we get to the value where
-- `next` was nil.
-- the table from the first loop of our for loop.
end
The for loop of your code does not preserve the previous value of list. list will end up containing the last line from the input. Your while loop will be infinite.
The for loop of their code saves the previous value of list inside the new list value. Their while loop changes l on each iteration. As a result, it prints a different value each time, and it stops when l is nil.
Related
Issue : I have some issues figuring out a way to select elements in my HTMLDocument which are under a certain point in the page.
In the following code sample, as you can see in the comments, I first select a part of them which respect my queryselector criteria
IEDoc.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']")
In this example I have 10 elements in this collection. Each of this element in contained in a table which is its parent on the 7th degree.
MsgBox TypeName(IEDoc.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']")(2).ParentNode.ParentNode.ParentNode.ParentNode.ParentNode.ParentNode.ParentNode) ' HTMLTable
Some of those elements are in the same table.
You can see here the form which contains all the tables .
Now, the thing is that I want to select the innerHTML of some of those elements only and not all of them. The criterion to know if I one of those 10 elements interests me or not is it's position on the webpage. I want all the elements which are under the message Part Usage. There is only one table containing the Part Usage text and so my idea was to see if the table in which are contained each element has a higher or lower index in the "form" collection.
If the index is higher I want this element, otherwise I discard it.
What I did for this is the following code :
I set the ID Bim to all the tables containing one or more
from the 10 elements.
For Each Element In IEDoc.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']") ' here for all of the 10 numbers found with the queryselectorall we'll find their respective table in the collection (form) and set its Class as "Bim". But since some of the numbers are in the same table, we won't have 10 tables with a classname "Bim" at the end of the process. We'll have only x tables with the classname "Bim"
Element.ParentNode.ParentNode.ParentNode.ParentNode.ParentNode.ParentNode.ParentNode.Class = "Bim"
Next
I set the ID Stop to the table containing the text Part Usage
For Each Element In IEDoc.getElementsByClassName("SectionHead")
If Element.innerHTML = "Part Usage" Then
'MsgBox TypeName(Element.ParentNode.ParentNode.ParentNode)' HTMLTable
Element.ParentNode.ParentNode.ParentNode.ID = "Stop"
End If
Next
I check which tables with the Classname Bim are under (=higher index) the table with the ID Stop. For the table ( there is actually only one) matching the criterion of point 3 I apply IEDoc.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']") inside of them so that I get all the elements in contains and more paricularly their innerHTML.
For Each Element In IEDoc.getElementsByClassName("Bim") ' Here we check all the x tables which have the Classname "Bim"
If Element.indexInTheWholeForm > IEDoc.getElementById("Stop").indexInTheWholeForm Then 'and compare somehow if their index in the (form) collection if higher than the table with the ID "Stop" ( this is similar to checking if the element if lower on the webpage in thic case) ( we only want the element which have a higher index aka under the Part Usage table)
For Each Element2 In Element.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']") ' Now we are in the table which contains the part numbers and we'll look for all the part numbers it contains by applying the queryselectorall again, but this time only in this specific table
array_parts2(iteration2) = Element.querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']")(iteration2).innerHTML
ActiveWorkbook.Worksheets(1).Cells(iteration2 + 1, 19) = array_parts2(iteration2)
iteration2 = iteration2 + 1
Next
End If
Next
of course what doesn't work is the indexInTheWholeForm property which doesn't exist. Any ideas on how to do this ?
Thank for reaching that line :)
Untested but I would do something like this (assuming I understood you correctly)
Sub Tester()
Const S_MATCH As String = "td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']"
Dim e, tbl, bHit As Boolean
'...
'load page etc
'...
'get all the matching rows and cycle though them
For Each e In IEDoc.querySelectorAll(S_MATCH)
'did we get to the table of interest yet?
If Not bHit Then
Set tbl = e.ParentNode.ParentNode.ParentNode.ParentNode. _
ParentNode.ParentNode.ParentNode
If IsPartUsageTable(tbl) Then bHit = True
End If
If bHit Then
'we reached the table of interest, so
' do something with e
End If
Next
End Sub
Function IsPartUsageTable(tbl) As Boolean
Dim e, rv As Boolean
For Each e In tbl.getElementsByClassName("SectionHead")
If Element.innerHTML = "Part Usage" Then
rv = True
Exit For
End If
Next
IsPartUsageTable = rv
End Function
Ok, so as unexpected as it sounds, I think I found a solution to my own question. I will confirm you that it works as soon as I have the possibility to run it with my colleague.
So I keep point 1 and 2 from my initial post and I replaced point 3 with the following :
For i = 0 To IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table").length
If IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table")(i).ID = "Stop" Then
index_Part_Usage = i
Position_Part_Usage = index + 1
Exit For
End If
Next
'MsgBox Position_Part_Usage
For i = 0 To IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table").length
If IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table")(i).className = "Bim" Then
index = i
Position = index + 1
If index > index_Part_Usage Then
For Each Element2 In IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table")(i).querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']") ' Now we are in the table which contains the part numbers and we'll look for all the part numbers it contains by applying the queryselectorall again, but this time only in this specific table
array_parts2(iteration2) = IEDoc.getElementsByTagName("form")(0).getElementsByTagName("table")(i).querySelectorAll("td[width='100'][class='ListMainCent'][rowSpan='1'][colSpan='1']")(iteration2).innerHTML
ActiveWorkbook.Worksheets(1).Cells(iteration2 + 1, 19) = array_parts2(iteration2)
iteration2 = iteration2 + 1
Next
End If
End If
Next i
So I need to screen scrape data off a website and return it to a spreadsheet based off if a charge amount matched as well the date was the most recent in the table. If there was simply one line in the table, the macro pulls that accordingly. So most of the code is good, I am connected to the website, pulling everything effectively. Where I am struggling is getting the logic to work where the two amounts match as well as the date being the most recent in the HTML table.
I guess what my question is how do I loop through Item(5) the column of that table and specify it to choose the most recent date, also setting the value so that it only finds the one equal to the charge amount. I only want a one to one match. I am new to this so if anyone wants to help me I would greatly appreciate it.
Set IHEC = iHTMLDoc.getElementsByTagName("TR")
If IHEC.Length > 2 Then
For index = 0 to IHEC.Length - 1
Set IHEC_TD = IHEC.Item(index).getElementsByTagName("TD")
Do Until IHEC.Length <2 Or index = IHEC.Length - 1
If IHEC.TD.Item(3).innerText = myBilledAmount Then
myItem1 = IHEC_TDItem(0).innerText
myItem2 = IHEC_TDItem(1).innerText
myItem3 = IHEC_TDItem(2).innerText
myItem4 = IHEC_TDItem(3).innerText
myItem5 = IHEC_TDItem(4).innerText
myItem6 = IHEC_TDItem(5).innerText
myItem7 = IHEC_TDItem(6).innerText
myItem8 = IHEC_TDItem(7).innerText
myItem9 = IHEC_TDItem(8).innerText
End If
End If
Loop
Next Index
I am working with a text file and need to call out the sum found from my last column of data [4] that I have made. I have done everything I need for the last column and have used total += square to add the first value in row one with the next value in row two and so on till I hit my 100th row in my text file. Now I need to be able to take my sum that I want in my 100 row and store it as a variable. How can I go about calling it out?
fullPath = open("localzscoretest.txt", "r") #Where I have our the current table located
import math
def globalchiSquare(fullPath):
for line in fullPath:
line = line.strip() #Strip it
lines = line.split(',') #split it
rows = lines[1:] #keeping the numbers
rows = map(float, rows) #getting my numbers in the .txt ready for the equation
square = (rows[4]**2) #squared the z score column
total += square
print total
globalchiSquare(fullPath)
change
square = (rows[4]**2) #squared the z score column
to be
square += (rows[4]**2) #squared the z score column
Give globalchiSquare a readlines() method in order to iterate.
In the function do
def globalchiSquare(fullPath):
for line in fullPath.readlines():
. . .
You should also keep your variables clear. When you say lines, it seems like you are saying that there are multiple--rows, too.
Just make it more simple and include the sum.
def globalchiSquare(fullPath):
total = 0
for line in fullPath.readlines(): # readlines() method
line = line.strip() # cut off ends
line = line.split(',') # create list
row = line[1:] # create row from line
row = map(float,row) # convert to floats
square = row[4]**2 # find square
print 'square',square
total += square
print 'total',total
return total
my_var = globalchiSquare(fullPath)
print my_var # should give total
EDIT: The return statement allows you to store the value of total.
def listc(favn):
num = 0
while num < favn :
num += 1
return num
list = []
i = int(raw_input("Input your favourite number : > "))
for num in range(0,i):
list.append(listc(i))
print list
The elements of the list are just same. Little iterations in code are sometime printing [None] in list also.
I want to generate a list with content as 1 to i.
There are two issues with your code.
First the while loop does not run 'favn' no. of times because the return statement is within while loop.It just runs single time, and everytime it returns 1.
Also, you should change
for num in range(0,i):
list.append(listc(i))
to
for num in range(0,i):
list.append(listc(num))
You will get the output you wanted.
If you want to generate a list from 1 to i, you can simply do list = range(1, i + 1).
I have caught myself in a issue, I know its not that difficult but I couldnt figure out how to implement it. I have an m file that looks like
clear;
PVinv.m_SwF=20e3
for m=1:1:70;
PVinv.m_SwF=PVinv.m_SwF+1e3;
Lmin = PVinv.InductanceDimens();
Wa_Ac = PVinv.CoreSizeModel();
PVinv.CoreSelect(Wa_Ac);
[loss_ind_core,loss_ind_copper] = PVinv.InductorLossModel(PVinv.m_L_Selected);
Total_Inductor_Loss=loss_ind_core+loss_ind_copper
plot(PVinv.m_SwF,Total_Inductor_Loss,'--gs');
hold on
xlim([10e3 90e3])
set(gca,'XTickLabel',{'10';'20';'30';'40';'50';'60';'70';'80';'90'})
grid on
xlabel('Switching Frequency [kHz]');
ylabel('Power loss [W]');
end
And the function that is of interest is CoreSelect(Wa_Ac)
function obj = CoreSelect(obj, WaAc)
obj.m_Core_Available= obj.m_Core_List(i);
obj.m_L_Selected.m_Core = obj.m_Core_Available;
end
I want to change the value of i from obj.m_Core_List(1) to obj.m_Core_List(27) within that for loop of main m file. How can I get the value of the function coreselect when I call it in main m file
For eg for m=1 to 70 I want the function to take the value of i=1 then execute till plot command and then same with but i=2 and so on
Any suggestion would be really helpful
I'm not sure I understand your question perfectly, but I think you want to pass an index i to the CoreSelect function, and loop i from 1 to 27 outside of the function. Try this:
function obj = CoreSelect(obj, WaAc, i)
...
end
for i=1:27,
PVInv.CoreSelect(WaAc,i);
end