Comparing two arrays or objects with a function in PHP

Comparing two arrays or objects with a function in PHP

Created:17 Aug 2017 16:07:40 , in  Maths

In this article I look how to compare two arrays against one another in PHP. For the purpose, I provide a flexible PHP class, which allows for comparisons of both arrays and objects whose internal working is based on array. The class, I called it SWWWArrayCompare, carries out comparisons using a function. It also allows you to compare arrays based on only certain slice of values in the arrays.

SWWWArrayCompare

Here is SWWWArrayCompare:


/*
  Class: SWWWArrayCompare 
  Description: Compare two arrays or objects using a comparing function
  Author: Sylwester Wojnowski
  WWW: wojnowski.net.pl

  Methods:
    instance - public static - compare two arrays or objects
      return - bool 
*/
class SWWWArrayCompare{
  public $result = true;
  private $opts = null;
  private $defaults = array(   
    'a' => null,
    'b' => null,
    // default reltion is greater than
    'relation' => '>',
    // name of length function if two objects are used 
    'len_func' => null,
    // name of value at the given index function 
    'index_func' => null,
    // objects / arrays to compare agains one another
    'a1' => null,
    'a2' => null
  );

  public static function instance($conf){
    $instance = new SWWWArrayCompare($conf);
    return $instance -> result;
  }

  public function __construct($conf){
    // configure
    $this -> opts = (object)array_merge($this -> defaults,$conf);
    // set interval of values to be compared
    $this -> setInterval(); 
    // get comparison result
    $this -> result = $this -> compare($this -> opts -> a1,$this -> opts -> a2);
  }

  // figure out what part of underlying array this comparison should work on
  private function setInterval(){
    // find lenghts of underlying arrays
    if($this -> opts -> len_func !== null){
      $a1_len = call_user_func(array($this -> opts -> a1,$this -> opts -> len_func));
      $a2_len = call_user_func(array($this -> opts -> a2,$this -> opts -> len_func));
    }else{
      $a1_len = count($this -> opts -> a1);
      $a2_len = count($this -> opts -> a2);
    } 
    // set number of items to iterate through 
    $this -> opts -> n = $n = $a1_len < $a2_len ? $a1_len : $a2_len;
    $a = $this -> opts -> a;
    $b = $this -> opts -> b;
    $this -> opts -> a = ($a !== null && $a > 0 && $a <= $n) ? $a : 1;
    $this -> opts -> b = ($b !== null && $b > 0 && $b <= $n) ? $b : $n;
  }

  // compare arrays / objects a1 agains a2  
  private function compare($a1,$a2){
    // set relation - provide comparing func unless one has been provided 
    $relation = is_string($this -> opts -> relation) ? Comparison::func($this -> opts -> relation) : $this -> opts -> relation;
  
    $n = $this -> opts -> b - $this -> opts -> a + 1;

    // empty arrays are equal to one another 
    if ( $n < 1 ) { return true; } 
     
    // compare two objects
    if( is_object($a1) and is_object($a2) ){
      while( $n > 0 ){
        $i = $this -> opts -> a + $n - 2;
        // break if relation is false 
        if( ! $relation(
          call_user_func(array($a1,$this -> opts -> index_func),$i),
          call_user_func(array($a2,$this -> opts -> index_func),$i)
          ) 
        ) { return false; }
        $n--;  
      }
    }

    // compare two arrays
    if( is_array($a1) and is_array($a2) ) {
      while( $n > 0 ){
        $i = $this -> opts -> a + $n - 2; 
        // break if relation is false 
        if( ! $relation($a1[$i],$a2[$i]) ){ return false; }
        $n--;
      }
    }
    return true;
  }  
}

Remarks

Before I move on to configuration and examples of use, I'm going to highlight some important facts about SWWWArrayCompare.

If two objects have to be compared using SWWWArrayCompare, the objects have to have public methods which return length and value at given index of underlying array.

If only a slice of the arrays has to be compared, its boundaries are specified using a and b configuration options. These values correspond to (present of not) indices in the shorter of two arrays. For array with indices from 0 through n - 1, their count starts from 1 and ends at n. Overshooting with either a or b causes no errors.

Deafault relation used for comparison is grater than. Different relation can be specified using a (anonymous) function.

If "relation" configuration option is not specified, it defaults to Comparison::func(), which returns greater of two numbers. Here is Comparison class:


// Number relations class
class Comparison{
  public static function func($relation = '>'){
    switch($relation){
      case '<':
        return function($a,$b){ return $a < $b; };
      case '>=':
        return function($a,$b){ return $a >= $b; };
      case '<=':
        return function($a,$b){ return $a <= $b; };
      default:
        return function($a,$b){ return $a > $b; };  
    }
  }
}

Comparison is a prerequisite for SWWWArrayCompare, hence must be included before the latter is used.

See examples section for concrete examples of these.

Configuration

SWWWArrayCompare accepts some configuration options. They are:

a - int - low index of slice of array to use for comparison

b - int - high index of slice of array to use for comparison

relation - string / function - default comparison relation defaults to '>' (greater than)

len_func - string - if two objects are being compared, this option specifies the name of public method which returns length of array to be compared.

index_func - string - if two objects are being compared, this option specifies the name of public method which returns value at given index in array to be compared.

a1,a2 - array / object - arrays / objects to compare against one another

Use examples

Here are some use examples.

Comparing two arrays using default comparing function:


SWWWArrayCompare::instance(
  array(
    'a1' => array(-1,3,5,10,30),
    'a2' => array(-2,2,4,9,16)
  )  
)
=> true

Return value in the above example means, that each item in array a1 is greater than item under the same index in a2 (default comparing function uses greater than relation to determine which item of the two passed to is greater). Hence a1 is greater than a2.

The next example is somewhat more involved example. In it two objects get compared.


class Custom{
  private $items = array();
      
  public function __construct($values){
    $items = $values;
  } 
      
  public function len(){
    return count($this -> items);
  }
      
  public function value($i){
    return $this -> items[$i];
  }
      
  public static function compare(){
    return function($a,$b){
      return ord($a) <= ord($b);
    };
  }  
}

The class above provides blueprint for objects to compare. Conveniently, it also provides a comparing function in the guise of a static method "compare". The comparing function specifies that ASCII value of string $a should be less or equal to ASCII value of string $b if it is to return true.

Here is how SWWWArrayCompare can be used to compare two objects of class Custom:


SWWWArrayCompare::instance(
  array(
    'a1' => new Custom(array('a','b','c','d')),
    'a2' => new Custom(array('a','z')),
    'len_func' => 'len',
    'index_func' => 'value',
    'relation' =>  Custom::compare()
  )  
);
=> true

Note, that in the above example the objects were given arrays of size 4 and 2 respectively. In such cases SWWWArrayCompare uses shorter of the two arrays to carry out comparison. Hence, ord('a') was compared against ord('a') and ord('b') was compared with ord('z').

Next example shows how to compare two arrays using just a slice of their values.


SWWWArrayCompare::instance(
  array(
    'a' => 2,
    'b' => 7,
    'relation' => '<', 
    'a1' => array(6,2,4,-1),
    'a2' => array(-2,6,16,7)
  )  
) 
=> true

In the above, slice length was specified using a and b configuration options. Values 2 and 7 mean, that only values under indices 1 and 6 were intended to be compared. However, since the arrays passed for comparison both have length 4, the real length of slice used by SWWWArrayCompare was 3 and it spanned indices 1 through 3 inclusive. Hence, 2 was compared, against 6, 4 against 16 and -1 against 7. Values at index 0 were not taken into account.

I hope these basic examples give enough insight into how SWWWArrayCompare works and what can be achieved with it.

Final thoughts

SWWWArrayCompare is a basic but very flexible tool which allows for effective comparisons of arrays and objects whose underlying working is based on array. As the next step, the class can be used for sorting and ultimately searching by array of values. I hope to shed more light on these topics in the future articles.

As always, I hope you'll find the code provided useful and examples simple enough to understand.

This post was updated on 17 Aug 2017 16:52:59

Tags:  php 


Author, Copyright and citation

Author

Sylwester Wojnowski

Author of the above article, Sylwester Wojnowski, is sWWW admin and owner.He enjoys doing Maths and studying algorithms, writing code in scripting and command languages, Thrash Metal music and playing electric guitar.

Copyrights

©Copyright, 2018 Sylwester Wojnowski. This article may not be reproduced or published as a whole or in parts without permission from the author. If you share it, please give author credit and do not remove embedded links.

Computer code, if present in the article, is excluded from the above and licensed under GPLv3.

Citation

Cite this article as:

Wojnowski, Sylwester. "Comparing two arrays or objects with a function in PHP." From sWWW - Code For The Web . https://wojnowski.net.pl//main/index/comparing-two-arrays-or-objects-with-a-function-in-php