<?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;
}
}
?>
|