Simple function to turn array of objects to array of key value pairs I have an application that has a lot of very complex objects that in most cases I only need to access an id value and a name value from. I'd like to reduce the overhead of serializing these large objects to JSON.  This is a simple function I created that takes an array of objects and returns an array of structures that contains only two keys, an id and a value.  This also needs to be compatible with CF8 servers.

I'd like to get some feedback on ways to make the code more expressive and any ways I can optimize this as well.

&lt;cffunction name="toKeyValuePairArray" returntype="Array" output="false" access="public"&gt;
    &lt;cfargument name="theArray" type="Array" required="true" hint="an array of objects" /&gt;
    &lt;cfargument name="idGetterFunctionName" type="string" /&gt;
    &lt;cfargument name="valueGetterFunctionName" type="string" /&gt;
        &lt;cfset var local = structNew() /&gt;
        &lt;cfset var retArray = [] /&gt;
        &lt;cfset var obj = {} /&gt;
        &lt;cfloop array="#arguments.theArray#" index="local.theComponent"&gt;
            &lt;cfset obj = {} /&gt;
            &lt;cftry&gt;
                &lt;cfinvoke component="#local.theComponent#" method="#arguments.idGetterFunctionName#" returnvariable="local.id" /&gt;
                &lt;cfinvoke component="#local.theComponent#" method="#arguments.valueGetterFunctionName#" returnvariable="local.value" /&gt;

                &lt;cfset obj.id = local.id /&gt;
                &lt;cfset obj.value = local.id /&gt;

                &lt;cfset arrayAppend(retArray,obj) /&gt;
            &lt;cfcatch&gt;&lt;/cfcatch&gt;
            &lt;/cftry&gt;
        &lt;/cfloop&gt; 

        &lt;cfreturn retArray /&gt;
&lt;/cffunction&gt;
Ryan,

Here's how I would do it. Since you're making something backwards compatible with CF8, which does not explicitly have the 'Local' scope, and you've already declared it via the 'var', then we'll put all other function local variables within this struct, and only return that which is needed.

&lt;!--- 
 *  FUNCTION toKeyValuePairArray
 *  Method to create a simple object reference array to reduce overhead and improve performance.
 *  This assumes that your objects have Getters for their primary properties.
 *  (no need to instantiate every object, every time, when all you need is a number or a name)
 *  
 *  @theArray (array) - an array of objects
 *  @idGetterFunctionName -  Function name for getter function that pulls the object's id
 *  @valueGetterFunctionName - Function name for getter function that pulls the object's name
 ---&gt;
&lt;cffunction name="ToKeyValuePairArray" returntype="array" output="false" access="public"&gt;
    &lt;cfargument name="theArray" type="Array" required="true" hint="an array of objects" /&gt;
    &lt;cfargument name="idGetterFunctionName" required="true" type="string" hint="Function name for getter function that pulls the object's id" /&gt;
    &lt;cfargument name="valueGetterFunctionName" required="true" type="string" hint="Function name for getter function that pulls the object's name" /&gt;

    &lt;cfset var LOCAL = StructNew() /&gt;
    &lt;cfset LOCAL.retArray = ArrayNew(1) /&gt;

    &lt;cfloop array="#ARGUMENTS.theArray#" index="LOCAL.theComponent"&gt;
        &lt;cfset LOCAL.tmpObjVals = StructNew() /&gt;
        &lt;cftry&gt;
            &lt;cfinvoke component="#LOCAL.theComponent#" method="#ARGUMENTS.idGetterFunctionName#" returnvariable="LOCAL.id" /&gt;
            &lt;cfinvoke component="#LOCAL.theComponent#" method="#ARGUMENTS.valueGetterFunctionName#" returnvariable="LOCAL.value" /&gt;

            &lt;cfset LOCAL.tmpObjVals["id"] = LOCAL.id /&gt;
            &lt;cfset LOCAL.tmpObjVals["value"] = LOCAL.value /&gt;

            &lt;cfset ArrayAppend(LOCAL.retArray,Duplicate(LOCAL.tmpObjVals)) /&gt;
            &lt;cfcatch&gt;&lt;!--- Empty Catch ---&gt;&lt;/cfcatch&gt;
        &lt;/cftry&gt;
    &lt;/cfloop&gt; 

    &lt;cfreturn LOCAL.retArray /&gt;
&lt;/cffunction&gt;


Since we 'var' one core variable (creating our own function local scope, so to speak) we no longer have to declare the temp object at the top of the method, since you reset it at the top of each loop iteration anyway. I also standardized your struct and array initialization across the method, to maintain that backward compatibility (and standardization of form is just good practice).

You aren't really doing any additional processing on the return variables from your 'getter' calls, so I applied them directly to the tempObj, so we don't create any unnecessary variables. You don't have to upper case scope names. I do that to make them stand out better when looking at code. I did uppercase the function names. This is just something I got from college: begin uppercase the function calls, and begin lowercase on variable names, then camel case the remainder.

NOTE: Adjusted some of my code, to work in some of Dan's (good) suggestions. I understand the 'try/catch' conceptually, but I did make them required args so it would throw errors if you didn't have them.