Location: PHPKode > scripts > Combinatory Logic > Combinatory.class.php
<?php
/**
* Class Combinatory
*    Creates and returns an Array with all possibilities for n vars with a k class.
*    For more info about Combinatory Logic, visits this site:
*        http://en.wikipedia.org/wiki/Combinatory_logic
* ------------------------------------------------------------------------
* EXAMPLES:
*    $container = Array( '3', '1', '2' );
*    $c = &new Combinatory('-'); // note that separator('-') is optional
*    $matches = &$c->result( $container, 2, "Cn,k" ); // 2 is the class or combination possibility, Pn is the method
*    // METHODS TO CALCULATE: Pn - Pn(k) - Dn,k - D'n,k - Cn,k - C'n,k
*
*    echo count( $matches );
*    echo '<pre>';
*    var_dump( $matches );
*    echo '</pre>';
*
*    //OUTPUT
*    3
*    array(3) {
*        [0]=>
*        string(3) "3-1"
*        [1]=>
*        string(3) "3-2"
*        [2]=>
*        string(3) "1-2"
*    }
*
* ________________________________________________________________________
* @author	Andrea Giammarchi
* @site		www.3site.it
* @date		13/10/2004
* @last_mod	22/01/2007 17:20 - tested with PHP 5.2 E_STRICT, removed few notices
* @compatibility	PHP4, 5, 5.2
* @version	1.0 tested
*/
class Combinatory {

	// VARIABLES
	/**
	 * 'private' var __loop:String            Used to create code for evaluation
	 * 'private' var __returnedValue:String        Used to create code inside __loop
	 * 'private' var __limit:Integer            Number of Elements Array keys
	 * 'private' var __matches:String        Array with dedicated combinations
	 * 'private' var __sep:String            Combinations separator
	 * 'private' var __delsep:Boolean        delete Combinations separator
	 * 'private' var __C:Array            Used to check variables to exclude
	 */
	var $__loop;
	var $__returnedValue;
	var $__limit;
	var $__matches;
	var $__sep;
	var $__delsep;
	var $__C;

	
	// CONSTRUCTOR
	/**
	 * 'public' constructor
	 *     Assigns separator if there is one
	 *
	 *        new Combinatory( [ $separator:String ] )
	 *
	 * @param    String        A separator that will divide found matches
	 */
	function Combinatory( $__sep = '' ) {
		if( $__sep == '' ) {
			$this->__sep = md5( microtime() );
			$this->__delsep = true;
		}
		else {
			$this->__sep = &$__sep;
			$this->__delsep = false;
		}
	}


	// PUBLIC METHODS
	/**
	 * 'public' method
	 *     Resets and assigns internal variables then switch $type and returns
	 *    dedicated type method.
	 *    If type mismatch switch returns an Array with only one key and with error as value.
	 *
	 *        Combinatory->result( $container:Array, $match:Integer, $type:String ):Array
	 *
	 * @param    Array        Elements container ( in Math, numbers of elements for n )
	 * @param    Integer        Possibilities for elements in container ( in Math, the class as k )
	 * @param    String        What type of matches do you need.
	 *                Options: Pn - Pn(k) - Dn,k - D'n,k - Cn,k - C'n,k
	 * @return    Array        An array class $match with all matches possibilities
	 */
	function result( $container, $match, $type ) {
		$this->__loop = '';
		$this->__returnedValue = '';
		$this->__limit = count( $container );
		$this->__matches = Array();
		$this->__C = Array();
		if( $match < 2 || $this->__limit < $match ) {
			return Array( 'This is not a good idea, please change elements or $match value .' );
		}
		switch( $type ) {
			case 'Pn':
				return $this->__checkReturn( $this->__combinatory_Pn( $container, $match ) );
			case 'Pn(k)':
				return $this->__checkReturn( $this->__combinatory_P1n( $container, $match ) );
			case 'Dn,k':
				return $this->__checkReturn( $this->__sort( $this->__combinatory_Pn( $container, $match ) ) );
			case 'D\'n,k':
				return $this->__checkReturn( $this->__sort( $this->__combinatory_P1n( $container, $match ) ) );
			case 'Cn,k':
				return $this->__checkReturn( $this->__combinatory_C( $container, $match, '__combinatory_Pn' ) );
			case 'C\'n,k':
				return $this->__checkReturn( $this->__combinatory_C( $container, $match, '__combinatory_P1n' ) );
			default:
				return Array( '$type error: options are "Pn" or "Pn(k)" or "Dn,k" or "D\'n,k" or "Cn,k" or "C\'n,k" .' );
		}
	}


	// PRIVATE METHODS
	/**
	 * 'private' method
	 *     Checks if separator was created automatically then remove it if necessary.
	 *
	 *        Combinatory->__checkReturn( &$container:Array ):Array
	 *
	 * @param    Array        Elements container
	 * @return    Array        Array with or without separator ( if was created automatically )
	 */
	function __checkReturn( $container ) {
		if( $this->__delsep === true ) {
			return str_replace( $this->__sep, '', $container );
		}
		else {
			return $container;
		}
	}
	
	/**
	 * 'private' method
	 *     Calls private __commonEvaluation method and returns private __codeCreator method
	 *
	 *        Combinatory->__combinatory_P1n( &$match:Integer, &$container:Array ):Array
	 *
	 * @param    Integer        Possibilities for elements in container
	 * @param    Array        Elements container
	 * @return    Array        Array created from private __codeCreator method
	 */
	function __combinatory_P1n( &$container, $match ) {
		$this->__commonEvaluation( $match );
		return $this->__codeCreator( $container );
	}
	
	/**
	 * 'private' method
	 *    Creates if statement inside evaluation to filter matches, then calls private
	 *     __commonEvaluation method with if statement and returns private __codeCreator method
	 *
	 *        Combinatory->__combinatory_Pn( &$match:Integer, &$container:Array ):Array
	 *
	 * @param    Integer        Possibilities for elements in container
	 * @param    Array        Elements container
	 * @return    Array        Array created from private __codeCreator method
	 */
	function __combinatory_Pn( &$container, &$match ) {
		$__possibilities = 'if( ';
		for( $a = 1; $a < $match; $a++ ) {
			for( $b = ($match-1); $b >= 0; $b-- ) {
				if( $a !== $b ) {
					$__possibilities .= '$_'.$a.' !== $_'.$b.' && ';
				}
			}
		}
		$__possibilities = substr( $__possibilities, 0, -3 );
		$this->__commonEvaluation( $match, $__possibilities.') { ', ' }' );
		return $this->__codeCreator( $container );
	}
	
	/**
	 * 'private' method
	 *    Evaluates right method to call and assigns them to a conventional array that
	 *    will be filtered inside a for statement that checks if values is just used or not.
	 *    Then returns parsed and filtered Array.
	 *
	 *        Combinatory->__combinatory_C( &$match:Integer, &$container:Array, $method:String ):Array
	 *
	 * @param    Integer        Possibilities for elements in container
	 * @param    Array        Elements container
	 * @param    String        Type of private method to use. Options: __combinatory_Pn / __combinatory_P1n
	 * @return    Array        Array created from private __codeCreator method and parsed from this method
	 */
	function __combinatory_C( &$container, &$match, $method ) {
		eval( '$cAr = $this->'.$method.'( $container, $match );' );
		$nAr = Array();
		for( $a = 0, $b = count( $cAr ); $a < $b; $a++ ) {
			$fAr = $this->__sort( $fAr = explode( $this->__sep, $cAr[$a] ) );
			if( in_Array( $fAr, $this->__C ) == false ) {
				array_push( $this->__C, $fAr );
				array_push( $nAr, $cAr[$a] );
			}
		}
		return $nAr;
	}
	
	/**
	 * 'private' method
	 *     Evaluates code created from other method and returns an Array with
	 *    all elements found.
	 *
	 *        Combinatory->__codeCreator( &$container:Array ):Array
	 *
	 * @param    Array        Elements container
	 * @return    Array        A new array with all combinatory matches for elements in container
	 */
	function __codeCreator( &$container ) {
		eval( $this->__loop );
		return $this->__matches;
	}
	
	/**
	 * 'private' method
	 *     Loops over matches to create a multi-for statement String to evaluate
	 *    with private __codeCreator method.
	 *
	 *        Combinatory->__commonEvaluation( &$match:Integer [, $pre:String [, $post:String ] ] ):Void
	 *
	 * @param    Integer        Possibilities for elements in container
	 * @param    String        DEFAULT: '' - other vars check to add inside loop if needed
	 * @param    String        DEFAULT: '' - end of other vars check inside loop if added
	 * @return    Void
	 */
	function __commonEvaluation( &$match, $pre = '', $post = '' ) {
		for( $a = 0; $a < $match; $a++ ) {
			$this->__loop .= 'for( $_'.$a.' = 0; $_'.$a.' < '.$this->__limit.'; $_'.$a.'++ ) { ';
			$this->__returnedValue .= '$container[$_'.$a.'].\''.$this->__sep.'\'.';
		}
		$rm = -( strlen( $this->__sep ) + 4 );
		$this->__loop .= $pre.'array_push( $this->__matches, '.substr( $this->__returnedValue, 0, $rm ).' );'.$post;
		for( $a = 0; $a < $match; $a++ ) {
			$this->__loop .= ' }';
		}
	}
	
	/**
	 * 'private' method
	 *    Sort array and returns them.
	 *
	 *        Combinatory->__sort( &$container:Array ):Array
	 *
	 * @param    Array        Elements container
	 * @return    Array        Elements container sorted
	 */
	function __sort( $container ) {
		sort( $container );
		reset( $container );
		return $container;
	}
}
?>
Return current item: Combinatory Logic