Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created September 24, 2020 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bennadel/23516c52a935624eeed39afd2ead4125 to your computer and use it in GitHub Desktop.
Save bennadel/23516c52a935624eeed39afd2ead4125 to your computer and use it in GitHub Desktop.
ArrayPop(), ArrayShift(), And ArraySliceSafe() In Lucee CFML 5.3.6.61
<cfscript>
// NOTE: The concepts of "left" and "right" on an Array mirror the existing concepts
// for Strings. Meaning, String.left( 1 ) gets index [ 1 ] on said string. As such,
// Array.left( 1 ) will also get index [ 1 ] on said array.
dump( arrayLeft( [], 3 ) );
dump( arrayLeft( [ "a" ], 3 ) );
dump( arrayLeft( [ "a", "b", "c", "d", "e", "f" ], 3 ) );
echo( "<br />" );
dump( arrayRight( [], 3 ) );
dump( arrayRight( [ "a" ], 3 ) );
dump( arrayRight( [ "a", "b", "c", "d", "e", "f" ], 3 ) );
echo( "<br />" );
dump( arrayRest( [] ) );
dump( arrayRest( [ "a", "b", "c" ] ) );
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
/**
* I return the N-LEADING values (at most) in the collection.
*
* @collection I am the collection being sliced.
* @count I am the number of leading values to include in the slice.
*/
public array function arrayLeft(
required array collection,
required numeric count
) {
return( arraySliceSafe( collection, 1, count ) );
}
/**
* I return the N-TRAILING values (at most) in the collection.
*
* @collection I am the collection being sliced.
* @count I am the number of trailing values to include in the slice.
*/
public array function arrayRight(
required array collection,
required numeric count
) {
var startIndex = ( collection.len() - count + 1 );
return( arraySliceSafe( collection, startIndex, count ) );
}
/**
* I return the N-1 trailing values in the collection.
*
* @collection I am the collection being sliced.
*/
public array function arrayRest( required array collection ) {
return( arraySliceSafe( collection, 2 ) );
}
/**
* I return a SHALLOW copy of the collection.
*
* @collection I am the collection being copied.
*/
public array function arrayCopy( required array collection ) {
return( arraySliceSafe( collection ) );
}
/**
* I perform a .slice() on the given collection, safely handling cases in which the
* startIndex or count go beyond the bounds of the collection - only the overlapping
* portions of the collection are returned.
*
* @collection I am the collection being sliced.
* @startIndex I am the (1-based) index at which to start slicing.
* @count I am the number of values to include in the slice.
*/
public array function arraySliceSafe(
required array collection,
numeric startIndex = 1,
numeric count = collection.len()
) {
var collectionLength = collection.len();
// NOTE: The endIndex in this case is INCLUSIVE - meaning, it is the last of the
// indices to be included in the resultant slice of values.
var endIndex = ( startIndex + count - 1 );
// If the given slice-range doesn't overlap with any of the indices in the given
// collection, then just return an empty array since no values will be sliced.
if (
! collectionLength ||
( count < 1 ) ||
( endIndex < 1 ) ||
( startIndex > collectionLength )
) {
return( [] );
}
// Clamp the slice-range down to the overlapping portion of the collection.
var safeStartIndex = max( 1, startIndex );
var safeEndIndex = min( collectionLength, endIndex );
var safeCount = ( safeEndIndex - safeStartIndex + 1 );
return( collection.slice( safeStartIndex, safeCount ) );
}
</cfscript>
<cfscript>
values = [ "a", "b", "c", "d" ];
while ( values.len() ) {
dump( arrayShift( values ) );
}
echo( "<br />" );
values = [ "a", "b", "c", "d" ];
while ( values.len() ) {
dump( arrayPop( values ) );
}
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
/**
* I remove the first item from the collection and return it. This MUTATES the given
* collection.
*
* @collection I am the collection being mutated.
*/
public any function arrayShift( required array collection ) {
return( arrayTakeAt( collection, 1 ) );
}
/**
* I remove the last item from the collection and return it. This MUTATES the given
* collection.
*
* @collection I am the collection being mutated.
*/
public any function arrayPop( required array collection ) {
return( arrayTakeAt( collection, collection.len() ) );
}
/**
* I remove and return the value at the given collection index. This MUTATES the given
* collection.
*
* @collection I am the collection being mutated.
* @targetIndex I am the index of the value being removed.
*/
public any function arrayTakeAt(
required array collection,
required numeric targetIndex
) {
if ( ! collection.indexExists( targetIndex ) ) {
throw(
type = "IndexOutOfBounds",
message = "Target index is not defined.",
detail = "arrayTakeAt() requires the index (#targetIndex#) to be defined."
);
}
var value = collection[ targetIndex ];
collection.deleteAt( targetIndex );
return( value );
}
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment