0

I have a loop within a loop leading to longer loading time of my page. With more data the loading time can go up to 10,000 ms, which is about 10 seconds. How can I write it for faster load time? The code I have so far:

            <cfloop from="#endDate#" to="#startDate#" index="i" step="#CreateTimeSpan(+1,0,0,0)#"> 

                <cfset loopdate = dateformat(i,'mmm dd')>

                <!---Loop the number of likes for each day--->
                <cfset daylike = 0>
                <cfset dayretweet = 0>
                <cfset tweetrec = now()>

                <cfloop from = 1 to = #arraylen(DeserializeJSON(cfhttp.fileContent))# index = "i">      
                    <cfset tweetrec = dateformat(DeserializeJSON(cfhttp.fileContent)[i].created_at,'mmm dd')>
                    <cfif tweetrec IS loopdate>
                        <cfset daylike = daylike + DeserializeJSON(cfhttp.fileContent)[i].favorite_count>
                        <cfset dayretweet = dayretweet + DeserializeJSON(cfhttp.fileContent)[i].retweet_count>
                    </cfif>
                </cfloop>

                <!---add the favourites to array--->
                <cfset myarray = ArrayAppend(likes, "#daylike#")>

                <!--- Append dates to dates array  --->
                <cfset myarray = ArrayAppend(dates, "#loopdate#")>

                <!---Append retweets to retweets array --->
                <cfset myarray = ArrayAppend(retweetarr, "#dayretweet#")>
            </cfloop>
3
  • 2
    How often do the input variations change? Daily? If so don't do it inline on every request, but instead set up a scheduled task to run every [period of change] (eg: daily) to do the processing and put the resultant data in the application scope, or some cache or the like. Commented Mar 3, 2016 at 9:45
  • 1
    You have DeserializeJSON(cfhttp.fileContent) four times in your code. It would be much more efficient to do that once before the first loop starts and store it in a new variable. You're currently doing the same process multiple times on the same string which isn't required. Also noticed your inner and outer loops both have index="i" they should be different. Commented Mar 3, 2016 at 11:14
  • As John pointed out, the biggest gains will be to move Deserialize outside the loop, and then turn this into 1 loop instead of 2. You also assign the result of ArrayAppend (which is just a true/false) to a variable which is completely ignored. You may be able to save a few cycles by switching to <cfset ArrayAppend(likes, "#daylike#")>, but this will be minor in comparison. Commented Mar 3, 2016 at 14:01

1 Answer 1

1

Looking at your code there are a few things you could do improve it.
You have DeserializeJSON(cfhttp.fileContent) four times in your code. It would be much more efficient to do that once before the first loop starts and store it in a new variable. You're currently doing the same process multiple times on the same string which isn't required. Also noticed your inner and outer loops both have index="i" they should be different.

Also as Adam said in the comments, if the data doesn't change very often then cache it / store it somewhere instead of re-calculating. A scheduled task would be good for this as the time it takes is not seen by the end user.

I think I'd probably look to refactor to only have one loop - so just loop over the dates that is in the returned JSON you are working with and make a new struct which contains the counts per day. So something like this:

<cfsavecontent variable="cfhttp.fileContent">[
        {
            "id": 1,
            "created_at": "1 January 2016",
            "favorite_count": 2,
            "retweet_count": 10
        },
        {
            "id": 2,
            "created_at": "2 January 2016",
            "favorite_count": 4,
            "retweet_count": 20
        },
        {
            "id": 3,
            "created_at": "2 January 2016",
            "favorite_count": 7,
            "retweet_count": 5
        },
        {
            "id": 4,
            "created_at": "2 January 2016",
            "favorite_count": 7,
            "retweet_count": 5
        }
]
</cfsavecontent>

<cfset data = DeserializeJSON(cfhttp.fileContent)>

<!--- convert data to get counts per day... --->
<cfset dataPerDay = {}>
<cfloop array="#data#" index="record">
    <!--- create a key which we can use to identity the date --->
    <cfset dateKey = DateFormat(record.created_at, "yyyymmdd")>
    <cfif structKeyExists(dataPerDay, dateKey)>
        <cfset dataPerDay[dateKey].favorite_count += record.favorite_count>
        <cfset dataPerDay[dateKey].retweet_count += record.retweet_count>
    <cfelse>
        <cfset dataPerDay[dateKey] = {
            favorite_count = record.favorite_count,
            retweet_count = record.retweet_count
        }>
    </cfif>
</cfloop>

<cfdump var="#dataPerDay#">

Running that will produce a struct with two keys 20160101 and 20160102 which will have the cumulative count of favourites and retweets for that day.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.