<commit_before><!--- PUBLIC MODEL CLASS METHODS --->

<cffunction name="average" returntype="any" access="public" output="false" hint="Calculates the average value for a given property. Uses the SQL function `AVG`. If no records can be found to perform the calculation on, a blank string is returned."
	examples=
	'
		<!--- Get the average salary for all employees --->
		<cfset avgSalary = model("employee").average("salary")>
	'
	categories="model-class,statistics" chapters="column-statistics" functions="count,maximum,minimum,sum">
	<cfargument name="property" type="string" required="true" hint="Name of the property to calculate the average for.">
	<cfargument name="where" type="string" required="false" default="" hint="An SQL fragment such as `lastName LIKE 'A%'` for example.">
	<cfargument name="include" type="string" required="false" default="" hint="Any associations that need to be included in the query.">
	<cfargument name="distinct" type="boolean" required="false" default="#application.wheels.functions.average.distinct#" hint="When `true`, `AVG` will be performed only on each unique instance of a value, regardless of how many times the value occurs.">
	<cfscript>
		var loc = {};
		if (ListFindNoCase("cf_sql_integer,cf_sql_bigint,cf_sql_smallint,cf_sql_tinyint", variables.wheels.class.properties[arguments.property].type))
		{
			// this is an integer column so we get all the values from the database and do the calculation in ColdFusion since we can't run a query to get the average value without type casting it
			loc.values = findAll(select=arguments.property, where=arguments.where, include=arguments.include);
			loc.totalRecords = 0;
			loc.total = 0;
			loc.done = "";
			for (loc.i=1; loc.i <= loc.values.recordCount; loc.i++)
			{
				loc.value = val(loc.values[arguments.property][loc.i]);
				if (!arguments.distinct || !ListFind(loc.done, loc.value))
				{
					loc.totalRecords++;
					loc.total = loc.total + loc.value;
					loc.done = ListAppend(loc.done, loc.value);
				}
			}
			loc.returnValue = loc.total / loc.totalRecords;
		}
		else
		{
			// if the column's type is a float or similar we can run an AVG type query since it will always return a value of the same type as the column
			arguments.type = "AVG";<commit_msg>refactor of average calculation avoid loop when distinct is false use arrays to calculate the average use struct for distinct values<commit_after><!--- PUBLIC MODEL CLASS METHODS --->

<cffunction name="average" returntype="any" access="public" output="false" hint="Calculates the average value for a given property. Uses the SQL function `AVG`. If no records can be found to perform the calculation on, a blank string is returned."
	examples=
	'
		<!--- Get the average salary for all employees --->
		<cfset avgSalary = model("employee").average("salary")>
	'
	categories="model-class,statistics" chapters="column-statistics" functions="count,maximum,minimum,sum">
	<cfargument name="property" type="string" required="true" hint="Name of the property to calculate the average for.">
	<cfargument name="where" type="string" required="false" default="" hint="An SQL fragment such as `lastName LIKE 'A%'` for example.">
	<cfargument name="include" type="string" required="false" default="" hint="Any associations that need to be included in the query.">
	<cfargument name="distinct" type="boolean" required="false" default="#application.wheels.functions.average.distinct#" hint="When `true`, `AVG` will be performed only on each unique instance of a value, regardless of how many times the value occurs.">
	<cfscript>
		var loc = {};
		if (ListFindNoCase("cf_sql_integer,cf_sql_bigint,cf_sql_smallint,cf_sql_tinyint", variables.wheels.class.properties[arguments.property].type))
		{
			// this is an integer column so we get all the values from the database and do the calculation in ColdFusion since we can't run a query to get the average value without type casting it
			loc.values = findAll(select=arguments.property, where=arguments.where, include=arguments.include);
			loc.values = ListToArray(ArrayToList(loc.values[arguments.property]));
			if(arguments.distinct)
			{
				loc.a = ArrayLen(loc.values);
				loc.s = {};
				for (loc.i=1; loc.i <= loc.a; loc.i++)
				{
					structinsert(loc.s, loc.values[loc.i], loc.values[loc.i], true);
				}
				loc.values = ListToArray(structkeylist(loc.s));
			}
			loc.returnValue = ArrayAvg(loc.values);
		}
		else
		{
			// if the column's type is a float or similar we can run an AVG type query since it will always return a value of the same type as the column
			arguments.type = "AVG";
{'fraction_non_alphanumeric': 0.1232906446711526, 'fraction_numerical': 0.0008682439765574126, 'mean_word_length': 4.612667478684531, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '791983', 'n_tokens_mistral': 1479, 'n_tokens_neox': 1335, 'n_words': 466}