极端重复循环

时间:2017-04-06 18:44:33

标签: applescript

使用我的Numbers表脚本,我遇到一个极端(每个单元格3-4秒)挂起重复循环,我相信这可能是由于我使用copy命令引起的,因为as我理解,copy创建了对值的新引用,而不是像set命令那样替换值。我不确定它是使用copy命令,我的Mac,还是在命令序列中放置不良的循环。我试过切换一系列无法​​帮助的命令序列。类似copy循环的其他用法表现得并不那么缓慢。我的问题是一个复合问题。我是否要求循环处理得多,是否放错位置,我应该使用copy之外的其他内容还是仅仅是我的Mac? (内存似乎不足以导致挂起,在挂起期间仍然剩下1.5gb,除了Numbers和脚本运行之外什么都没有)总结一下,我该如何解决挂起问题?

挂起开始的循环部分位于

之下
-- This is where the extreme hang begins

repeat with x from 1 to (count rows) - 2
    repeat with y from 1 to count monthNames
        copy incrementDates(y) of me to {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
        set monthStart to theDateString
        set monthEnd to theMonthIndex & "/" & monthLengthInDays & "/" & theYear as text
        set theFormula to "=SUMIFS(Amount,Category,A,Date, \">=" & monthStart & "\",Date, \"<=" & monthEnd & "\")"
        set value of cell (y + 1) of row (x + 1) to theFormula
    end repeat
end repeat

-- Extreme hang ends and script continues normally

这里有完整的参考脚本,如果是我的其他copy用法的复杂问题。

set moneyInHeaders to {"Last Name", "First Name", "Receipt Number", "Payment", "Date", "Office", "City", "Referral Name"}
set locationList to {"Location 1", "Location 2"}
set the monthNames to {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
set moneyOutHeaders to {"Expense", "Amount", "Date", "Category", "Item"}
set categoryItems to {"Marketing", "Software", "Tools", "Utilities", "Other"}
set thisYearName to (year of (current date)) as string
set moneyInColor to {31354, 51657, 22615}
set moneyOutColor to {59623, 20816, 14391}

tell application "Numbers"
if not (exists document 1) then make new document
tell document 1
    delete every sheet
    set the name of sheet 1 to "Money In"
    tell sheet 1
        delete every table
        set moneyInTable to make new table with properties {name:"Money In", position:{-7, 29}, width:788, column count:count moneyInHeaders, row count:14, footer row count:1, header column count:2}
        tell moneyInTable
            set locationCount to count locationList -- get count of locations
            set properties of row 1 to {background color:{moneyInColor}}
            my populateCells(moneyInTable, row 1, moneyInHeaders, false) -- fill header row values
            set value of last cell of column named "Payment" to ("=SUM(C)")
            my populateCells(moneyInTable, column named "Office", locationList, true) -- fill pop up menu values
            my formatCells(moneyInTable, column named "Payment", currency)
            my formatCells(moneyInTable, column named "Date", date and time)
            my formatCells(moneyInTable, column named "Office", pop up menu)
            delete (rows 2 through (locationCount + 1)) -- remove rows that contain values so the pop up column is empty
            repeat locationCount times -- add the rows back to keep table size
                add row below row 2
            end repeat
        end tell -- end telling moneyInTable

        -- Set locked false for now
        set totalsTable to make new table with properties {name:"Money In Totals", locked:false, position:{785, 29}, column count:2, row count:(count monthNames) + 2, header column count:1, header row count:1, footer row count:1}
        tell totalsTable
            set properties of row 1 to {background color:{moneyInColor}}
            my populateCells(totalsTable, column "A", monthNames, true)
            set value of last cell of column "A" to "Grand Total"
            set value of cell "B1" to "Totals"
            set value of last cell to ("=SUM(B)")
            tell column "B"
                repeat with x from 1 to count monthNames -- loop and increment dates for the SUMIFS formula
                    copy incrementDates(x) of me to {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
                    set monthStart to theDateString
                    set monthEnd to theMonthIndex & "/" & monthLengthInDays & "/" & theYear as text
                    set the value of cell (x + 1) to ("=SUMIFS(Payment,Date, \">=" & monthStart & "\", Date, \"<=" & monthEnd & "\")")
                end repeat
            end tell -- end telling column B
        end tell -- end telling totalsTable
    end tell -- end telling active sheet

    make new sheet with properties {name:"Money Out"}
    tell sheet 2
        delete every table
        set moneyOutTable to make new table with properties {name:"Money Out", position:{-7, 29}, width:710, column count:count moneyOutHeaders, row count:14, footer row count:1}
        tell moneyOutTable
            set catCount to count categoryItems -- get count of categoryItems
            set properties of column "A" to {width:180}
            set properties of row 1 to {background color:{moneyOutColor}}
            set value of last cell of column "B" to ("=SUM(B)")
            my populateCells(moneyOutTable, row 1, moneyOutHeaders, false) -- fill header row values
            my populateCells(moneyOutTable, column named "Category", categoryItems, true) -- fill pop up values
            my formatCells(moneyOutTable, column "A", text)
            my formatCells(moneyOutTable, column named "Amount", currency)
            my formatCells(moneyOutTable, column named "Date", date and time)
            my formatCells(moneyOutTable, column named "Category", pop up menu)
            my formatCells(moneyOutTable, column named "Item", text)
            delete (rows 2 through (catCount + 1)) -- remove rows that contain values so the pop up menu is empty
            repeat catCount times -- add the rows back to keep table size
                add row below row 2
            end repeat
        end tell -- end telling moneyOutTable

        set totalsTable to make new table with properties {name:"Money Out Totals", locked:false, position:{744, 29}, column count:2, row count:(count monthNames) + 2, header column count:1, header row count:1, footer row count:1}
        tell totalsTable
            set properties of row 1 to {background color:{moneyOutColor}}
            my populateCells(totalsTable, column "A", monthNames, true)
            set value of last cell of column "A" to "Grand Total"
            set value of cell "B1" to "Totals"
            set value of last cell to ("=SUM(B)")
            tell column "B"
                repeat with x from 1 to count monthNames -- oop and increment dates for the SUMIFS formula
                    copy incrementDates(x) of me to {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
                    set monthStart to theDateString
                    set monthEnd to theMonthIndex & "/" & monthLengthInDays & "/" & theYear as text
                    set theFormula to ("=SUMIFS(Amount,Date, \">=" & monthStart & "\", Date, \"<=" & monthEnd & "\")")
                    set the value of cell (x + 1) to theFormula
                end repeat
            end tell -- end telling column B
        end tell -- end telling totalsTable

        set summaryTable to make new table with properties {name:"Category Totals", position:{943, 29}, column count:2, row count:(catCount) + 1}
        tell summaryTable
            set properties of row 1 to {background color:{moneyOutColor}}
            set value of cell "B1" to "Totals"
            my populateCells(summaryTable, column "A", categoryItems, true)
            my formatCells(summaryTable, column "B", currency)
            tell column 2
                repeat with x from 2 to the count of cells
                    set theFormula to ("=SUMIFS(Amount,Category,A)")
                    set the value of cell x to theFormula
                end repeat
            end tell -- end telling column 2
        end tell -- end telling summaryTable

        -- Extreme hang starts on this table, specifically below where noted

        set breakDownTable to make new table with properties {name:"Expenses By Month", column count:(count monthNames) + 1, row count:(count categoryItems) + 2, header column count:1, footer row count:1, header row count:1}
        tell breakDownTable
            set properties of row 1 to {background color:{moneyOutColor}}
            my populateCells(breakDownTable, row 1, monthNames, true)
            my populateCells(breakDownTable, column "A", categoryItems, true)
            my formulateRow(breakDownTable, last row, "SUM")
            set selection range to range "B2:M8"
            set properties of selection range to {format:currency}
            set value of last cell of column "A" to "Total"

--***** This is where the extreme hang begins

            repeat with x from 1 to (count rows) - 2
                repeat with y from 1 to count monthNames
                    copy incrementDates(y) of me to {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
                    set monthStart to theDateString
                    set monthEnd to theMonthIndex & "/" & monthLengthInDays & "/" & theYear as text
                    set theFormula to "=SUMIFS(Amount,Category,A,Date, \">=" & monthStart & "\",Date, \"<=" & monthEnd & "\")"
                    set value of cell (y + 1) of row (x + 1) to theFormula
                end repeat
            end repeat

--***** Extreme hang ends and script continues normally

            add column after last column -- add a totals column after everything else is done
            set totalsColumn to the last column
            tell totalsColumn
                set value of cell 1 to "Total"
                my formulateColumn(breakDownTable, totalsColumn, "SUM")
            end tell -- end telling totalsColumn
        end tell -- end telling breakDownTable
    end tell -- end telling sheet 2

    make new sheet with properties {name:"Overview"}
    tell sheet 3
        delete every table
        set cashFlowTable to make new table with properties {name:"Cashflow", column count:2, row count:(count monthNames) + 2, footer row count:1}
        tell cashFlowTable
            my populateCells(cashFlowTable, column "A", monthNames, true)
            set value of last cell of column "A" to "Grand Total"
            my formatCells(cashFlowTable, column "B", currency)
            set value of cell "B1" to "Cashflow Totals"
            set value of last cell to ("=SUM(B)")
            tell column 2
                repeat with x from 1 to count monthNames
                    set value of cell (x + 1) to ("=Money In::Money In Totals::Totals " & item x of monthNames & "−Money Out::Money Out Totals::Totals " & item x of monthNames)
                end repeat
            end tell -- end telling column 2
        end tell -- end telling cashflow table
    end tell -- end telling sheet 3
    set active sheet to first sheet
end tell -- end telling document
end tell -- end telling Numbers

using terms from application "Numbers"

to populateCells(theTable, theDirection, theListToUse, usingHeaders)
    tell theTable
        set x to 1
        if usingHeaders is true then
            repeat with x from 1 to count theListToUse
                set value of cell (x + 1) of theDirection to (item x of theListToUse)
            end repeat
        else
            repeat with x from 1 to count theListToUse
                set value of cell x of theDirection to (item x of theListToUse)
            end repeat
        end if
    end tell
end populateCells

to formatCells(theTable, theDirection, theFormat)
    tell theTable
        set theRange to ¬
            ((name of cell 2 of theDirection) & ":" & ¬
                (name of last cell of theDirection))
        set selection range to range theRange
        set properties of selection range to {format:theFormat}
    end tell
end formatCells

to colorCells(theTable, theDirection, theColor)
    tell theTable
        set theRange to ¬
            ((name of cell 2 of theDirection) & ":" & ¬
                (name of last cell of theDirection))
        set selection range to range theRange
        set properties of selection range to {background color:theColor}
    end tell
end colorCells

to formulateColumn(theTable, theColumn, theType)
    tell theTable
        tell theColumn
            repeat with i from 2 to the count of cells
                set thisRow to the row of cell i
                set rangeStart to the name of cell 2 of thisRow
                set rangeEnd to the name of cell -2 of thisRow
                set theFormula to ("=" & theType & "(" & rangeStart & ":" & rangeEnd & ")") as string
                set value of cell i to theFormula
            end repeat
        end tell
    end tell
end formulateColumn

to formulateRow(theTable, theRow, theType)
    tell theTable
        tell theRow
            repeat with i from 2 to the count of cells
                set thisColumn to the column of cell i
                set rangeStart to the name of thisColumn
                set rangeEnd to the name of thisColumn
                set theFormula to ("=" & theType & "(" & rangeStart & ":" & rangeEnd & ")") as string
                set value of cell i to theFormula
            end repeat
        end tell
    end tell
end formulateRow

end using terms from

to incrementDates(tempMonth)
     copy (current date) to tempDate
     set day of tempDate to 1
     set month of tempDate to tempMonth
     set theDayName to weekday of tempDate
     set theDayIndex to day of tempDate
     set theMonth to month of tempDate
     set theMonthIndex to theMonth as integer
     set theMonthName to theMonth as string
     set theYear to year of tempDate
     set theDateString to short date string of tempDate
     repeat with i from 1 to 32
         set tempDate to tempDate + (1 * days)
         if month of tempDate is not theMonth then
             set monthLengthInDays to i
             exit repeat
         end if
     end repeat
     return {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
end incrementDates

1 个答案:

答案 0 :(得分:0)

查看了您的脚本后,我已经运行了它并且没有遇到您所描述的滞后现象,因此在编写脚本时会将问题留给您的系统或多次测试运行。

接下来,如上面的评论所述,您可以在set处理程序中使用copy命令而不是incrementDates。每次调用处理程序时(每次调用12次),您都不需要(current date)的副本,因此可以更改为

to incrementDates(tempMonth)
     set tempDate to (current date)
     set day of tempDate to 1
     set month of tempDate to tempMonth
     set theDayName to weekday of tempDate
     set theDayIndex to day of tempDate
     set theMonth to month of tempDate
     set theMonthIndex to theMonth as integer
     set theMonthName to theMonth as string
     set theYear to year of tempDate
     set theDateString to short date string of tempDate
         repeat with i from 1 to 32
         set tempDate to tempDate + (1 * days)
         if month of tempDate is not theMonth then
             set monthLengthInDays to i
             exit repeat
         end if
     end repeat
     return {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
end incrementDates

从那里你仍然会检索你正在做的值。

接下来,您还在此处创建了一个处理程序,其中并不特别需要处理程序。

to formatCells(theTable, theDirection, theFormat)
    tell theTable
        set theRange to ¬
        ((name of cell 2 of theDirection) & ":" & ¬
            (name of last cell of theDirection))
    set selection range to range theRange
    set properties of selection range to {format:theFormat}
end tell
end formatCells

以上与使用

相同
set properties of column named "Payment" to {format:currency}

差异可以忽略不计,但我的一般指南并没有重新发明轮子。您还没有使用在创建totalsTable

时可以使用处理程序的处理程序
to makeMonthlyTotalsTable(theTable, theColor)
    tell theTable
        set properties of row 1 to {background color:{theColor}}
        my populateCells(totalsTable, column "A", monthNames, true)
        set value of last cell of column "A" to "Grand Total"
        set value of cell "B1" to "Totals"
        set value of last cell to ("=SUM(B)")
        tell column "B"
            repeat with x from 1 to count monthNames -- loop and increment dates for the SUMIFS formula
                copy incrementDates(x) of me to {theDayIndex, theMonthIndex, theYear, theDateString, monthLengthInDays}
                set monthStart to theDateString
                set monthEnd to theMonthIndex & "/" & monthLengthInDays & "/" & theYear as text
                set the value of cell (x + 1) to ("=SUMIFS(Payment,Date, \">=" & monthStart & "\", Date, \"<=" & monthEnd & "\")")
            end repeat
        end tell -- end telling column B
    end tell -- end telling totalsTable
end makeMonthlyTotalsTable

如果您计划在其他工作表中重新创建该表,那么可以忽略不计的差异和意见,但更清晰的代码。

注意:我没有测试这个处理程序,我只是从你的脚本中复制并粘贴它并将变量名称更改为通过,但只要你设置并声明颜色名称变量并切换它就应该运行正常monthNames属性。

property monthNames : {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}