J. Miller Posted November 4, 2011 Share Posted November 4, 2011 Hello, I am trying to build a Summary array (xArraySummary} from an array of Lighting Fixtures (xArray) I want to get a total (IntelCnt) of each type of Fixture (IntelInstType) The xSummaryArray is to be used in my script to build a list of instruments in a dialog Being more of a dabbler and not an ace programmer I was wondering if there is an easier way to do this (nested loops ?, which always make me loopy} Does this make sense to anyone? {************************** SAMPLE CODE ***************************************} TYPE IntelData = STRUCTURE IntelHan, IntelRecHan : HANDLE; IntelInstType : STRING; IntelCnt : INTEGER; END; CONST kMaxArray = 200; VAR xArray, xArraySummary : Array[1..kMaxArray] of IntelData intNum, arrayCnt , intVar : INTEGER; holderString : STRING; IF intVar > 0 THEN BEGIN {intVar determines if sort should happen} xArraySummary[1].IntelInstType := xArray[1].IntelInstType; {put 1st xArray Element into xArraySummary} intNum := 1; {declare variable} arrayCnt := 1; {declare variable} FOR i := 1 TO noNumChan DO BEGIN {loop thru xArray} holderString := xArray.IntelInstType; arrayCnt := 1; WHILE arrayCnt <> kMaxArray DO BEGIN {IF NAMES ARE THE SAME GET OUT OF LOOP} IF xArraySummary[arrayCnt].IntelInstType = holderString THEN BEGIN xArraySummary[arrayCnt].IntelCnt := xArraySummary[arrayCnt].IntelCnt +1; {counts qty of fixtures} arrayCnt := kMaxArray; {kill the while loop} END {IF NAMES DONT MATCH ADD 1 to arraycnt to look at next element} ELSE IF (xArraySummary[arrayCnt].IntelInstType <> holderString) AND (xArraySummary[arrayCnt].IntelInstType <> '') THEN BEGIN arrayCnt := arrayCnt +1; END {IF NAMES DONT MATCH AND IS BLANK PUT NAME IN ARRAY} ELSE BEGIN xArraySummary[arrayCnt].IntelInstType := holderString; xArraySummary[arrayCnt].IntelCnt := xArraySummary[arrayCnt].IntelCnt +1; {counts qty of fixtures} intNum := intNum +1; { will determine how many fixtures i need to list in my dialog} arrayCnt := kmaxArray; {kill the while loop} END; END; END; END; {******************************** SAMPLE CODE *************************************} Thanks Jeff Miller Quote Link to comment
Miguel Barrera Posted November 7, 2011 Share Posted November 7, 2011 I follow most of the code except the last condition where it could be blank. If xArray is filled consecutively with all the fixtures in the document, then a blank record would be the end of the array, so why would you need to fill another record? How are you adding data to the xArray? Are the fixtures the same PIO? Quote Link to comment
Pat Stanford Posted November 8, 2011 Share Posted November 8, 2011 I don't know if this is simpler or not, but I think this can be done with two nested For statements. I have simplified this (and obviously not run it) to skip the field part of the array filling and matching. This version avoids the need to set the counters high to artificially kill the loop. Pat Begin xArraySummary[1] := xArray[1]; arrayCnt :=1; For i := 2 to noNumChan do Begin k:=0; {set counter to see if we have processed every item in the Summary] For j:= 1 to arrayCnt do {set counter for number of rows in Summary] Begin If xArraySummary[j] <> xArray[i] do k := k +1; {increment for rows that don't match} End; If k = arrayCnt do {if k is the same as the arrayCnt then we did not match in Summary} Begin arrayCnt := arrayCnt +1; xArraySummary[arrayCnt] := xArray[i]; End; End; End; Quote Link to comment
ccroft Posted November 10, 2011 Share Posted November 10, 2011 Are you doing something else with xArray besides summarizing it with another array? IE does xArray exist only to be summarized? If so, I'd do the counting while loading xArray. The loading procedure looks at an object. If it's not been seen before it adds it to the array. If the name is on the array it increments the count and moves on to next object. You'd need a two dimensional array. Column one is intelCount and two is intelData. Of course, you may have needs that disqualify this approach, but if not it seems a lot simpler to me. The entire loading and counting is done within one loop, there's one less array to manage, and one less array to traverse. My apologies if I'm stating the obvious. Quote Link to comment
ccroft Posted November 11, 2011 Share Posted November 11, 2011 Here's how I've looked at values and added to array, or counted them if they were already in the array. It's the same approach if the values are in another array, or the values are derived from a PIO. In my EG I already have two procedures: sameValue and newValue. You already know what each does. You could write out the procedures directly in the loop if it made more sense to you. In any case, the last thing that happens in each is that a boolean becomes true. If conditions are met and either procedure runs then 'done' becomes true, we exit the loop and move on to the next value to either be counted or added to the array. If neither condition is met then done stays false and we move to the next location in the array until one of the procedures runs, and then we're done with that value. pioName:= aValueFromArrayOrObject done := false; index:= 1 While (not done) Do Begin If array[index] = 0 then newValue else IF array[index] = pioName then sameValue; index := index+1; End; This could be a procedure in a ForEach statement. ForEach looks at every object in the drawing that matches your criteria, gets it's name and then runs above to either load the array or increment the counter in the array accordingly. With this approach you build one properly summarized array from the get go. This *might* be a more efficient way, but if what you've got is working for you well... why rock the boat? Quote Link to comment
J. Miller Posted November 11, 2011 Author Share Posted November 11, 2011 Hello, Thank you so much for your comments. Sorry it took so long to get back, but it has been one of those weeks. I hope to get back to this project this weekend and will take the posted information and evaluate it. It always inspiring to see how others code and to see if I am anywhere in the ballpark at times, especially with arrays and nested for loops. Jeff Miller Quote Link to comment
ccroft Posted November 11, 2011 Share Posted November 11, 2011 Hi Jeff, I actually haven't written anything meaningful in quite some time, and I'd like to thank you for posting and tweaking my interest again, and trying to see what you were up to. If I may I'd make a couple more comments. I think you'll find that you're doing a few things in your code that don't need to be done. You don't need to have a separate "fill the first location" line. My example handles that in the first line of the loop. IE the first time we look at the array we can assume that it's blank. Actually, some might say that we need some error checking to make sure, but I've never done that and in some 8 years of using a tool daily that doesn't check I haven't had a failure. Also, the section at your comment {IF NAMES DONT MATCH ADD 1 to arraycnt to look at next element} isn't needed if you increment the index after the logic is finished evaluating things. If neither condition is met, then the index increments to look at the next location in the array. So let's say we're on the fifth instrument and it hasn't yet been entered into the array. The logic looks at each value in the array consecutively and doesn't find a match. It then encounters a blank location. That means that we've looked at every instrument in the array, so we add the value there. You can use the way an array is filled to your advantage. The fact that I'm using 'done' to control the loop is essentially the same as what you're doing with: arrayCnt := kmaxArray; I've just rearranged things a bit. On the subject of error checking: you may want to add a safety valve in case something funky starts happening. Something like: While (not done) | (index < arrayCnt) Do.... If arrayCnt = kMaxArray then done := true; AlertMessage('funkiness encountered)'; I have something like that in a script, but it's never gotten funky. :-( Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.