Close

Some useful non-associative Array Functions for PHP

A friend of mine once said he was good at a lot of things, but he wasn't an expert at anything. Well, that's sort of how I feel about the capabilities of the PHP language. PHP developers seem to be at the forefront of stretching existing functionality to the widest extremes. It really does have a lot of great functionality, and integration built in, but when you get down to it, there are still a lot of rudimentary functions that are still left to Developers to create on their own.
This page is here to provide some array functions that I would like to make Open Source (according to the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version). The code that I am including below includes both a number of useful functions as well as a brief explanation of what they do and examples for how they can be used.

Non-Associative (NA) Array Functions

All of the following functions are designed to handle non-associative arrays. That means that generally speaking, the indexes of the arrays have no significance, only the keys matter.  Some languages call these lists, and other languages call PHP arrays “hashes”, so the definition of an array is really a matter of semantics, and in this case we are talking about non-associative arrays like: array(“one”, “two”, “three”), not: array(“one”=>”a”, “two”=>”b”, “three”=>”c”).

One key point to notice however about these functions is that they operate on multiple arrays, not just two as many programmers usually write for themselves. 

Note also that these functions were written to work with PHP 5.6 and up. The accepting argument syntax would have to be modified slightly to work with earlier versions.

na_array_merge (...$arrays); aka: Union or Logical Disjunction
function na_array_merge(...$arrays){
  $transposed_array = array();
  $finished_array = array();
  foreach($arrays as $array){
    $temp_array = array_count_values($array);
    //// tally the temp_array to the collective transposed_array
    foreach ($temp_array as $key => $value){
      if (!isset($transposed_array[$key]) or $value > $transposed_array[$key]){
        $transposed_array[$key] = $value;
      }////otherwise don't add it.
    }
  }
  //// transpose the array back:
  foreach ($transposed_array as $key => $value){
    $finished_array = array_merge($finished_array,array_fill(0,$value,$key));
  }
  return $finished_array;
}

$array1=array(“3″,”1″,”2″,”3″,”a”,”3″,”b”,”3″,”5″);
$array2=array(“3″,”1″,”3″,”3″,”4″,”6”);
$array3=array(“3″,”1″,”2″,”4″,”7”);

echo(implode(“, “,na_array_merge($array1,$array2,$array3)));

PRODUCES:

3, 3, 3, 3, 1, 2, a, b, 5, 4, 6, 7

Note that even though there are more than four “3”s among the arrays above, only four are unique to any particular array, and if you were to create a venn diagram with these arrays, you would only see the four “3”s.

na_array_diff (...$arrays); // an exclusion of all common elements
function na_array_diff(...$arrays){
  $finished_array = array();
  $array_list = array();
  $uniq_list = array();
  foreach($arrays as $array){
    array_push($array_list,array_count_values($array));
    $uniq_list = array_unique(array_merge($uniq_list,array_values($array)));
  }
  foreach ($uniq_list as $key){
    $count = 0;
    $max_count = -1;
    $second_max_count = -1;
    foreach ($array_list as $temp_array){
      if (isset($temp_array[$key]) and ($max_count < 0 or $temp_array[$key] > $array_list[$max_count][$key])){
        $second_max_count = $max_count;
        $max_count = $count;
      }elseif(isset($temp_array[$key]) and ($second_max_count < 0 or $temp_array[$key] > $array_list[$second_max_count][$key])){
        $second_max_count = $count;
      }
      $count++;
    }
    if(!isset($array_list[$max_count][$key])){
      $array_list[$max_count][$key] = 0;
    }
    if(!isset($array_list[$second_max_count][$key])){
      $array_list[$second_max_count][$key] = 0;
    }
    $num_of_keys = $array_list[$max_count][$key] - $array_list[$second_max_count][$key];
    if ($num_of_keys){
      $finished_array = array_merge($finished_array,array_fill(0,$num_of_keys,$key));
    }
  }
  return $finished_array;
}

$array1=array(“3″,”1″,”2″,”3″,”a”,”3″,”b”,”3″,”5″);
$array2=array(“3″,”1″,”3″,”3″,”4″,”6”);
$array3=array(“3″,”1″,”2″,”4″,”7”);

echo(implode(“, “,na_array_diff($array1,$array2,$array3)));

PRODUCES:

3, a, b, 5, 6, 7

Note that the only “3” that is returned is the one that is not also intersected with “3”s from other arrays.

na_array_intersect (...$arrays); // elements that intersect all arrays
function na_array_intersect(...$arrays){
  $transposed_array = array();
  $finished_array = array();
  $array_list = array();
  $uniq_list = array();
  foreach($arrays as $array){
    array_push($array_list,array_count_values($array));
    $uniq_list = array_unique(array_merge($uniq_list,array_values($array)));
  }
  foreach ($uniq_list as $key){
    $count = 1;
    $last_count = count($array_list);
    $min_num_of_value = 0;
    foreach ($array_list as $temp_array){
      if (isset($temp_array[$key])) {
        if ($count == $last_count ){
          //// this means we found the element in every array, so keep track of the smallest number of values of it
          if (!$min_num_of_value or $temp_array[$key] < $min_num_of_value){
            $transposed_array[$key] = $temp_array[$key];
          }else{
            $transposed_array[$key] = $min_num_of_value;
          }
        }elseif(!$min_num_of_value or $min_num_of_value > $temp_array[$key] ){
          $min_num_of_value = $temp_array[$key];
        }//// otherwise it was found, but this array has more, so don't change anything.
      }else{
        ////otherwise don't add it. and skip to the next element int the uniq_list
        break;
      }
      $count++;
    }
  }
  //// transpose the array back:
  foreach ($transposed_array as $key => $value){
    $finished_array = array_merge($finished_array,array_fill(0,$value,$key));
  }
  return $finished_array;
}

$array1=array(“3″,”1″,”2″,”3″,”a”,”3″,”b”,”3″,”5″);
$array2=array(“3″,”1″,”3″,”3″,”4″,”6”);
$array3=array(“3″,”1″,”2″,”4″,”7”);

echo(implode(“, “,na_array_intersect($array1,$array2,$array3)));

PRODUCES:

3, 1

Note that the only “3” that is returned is the one that is the one that is in common with all other arrays.

na_array_xnor (...$arrays);
function na_array_xnor(...$arrays){
  $xnor = array();
  $na_array_intersection = call_user_func_array('na_array_intersection',$arrays);
  $true_combination  = call_user_func_array('na_array_merge',$arrays);
  $na_array_diff   = call_user_func_array('na_array_diff',$arrays);
  //// xnor = (combination - diff) - intersection
  $xnor = na_array_diff($true_combination,$na_array_diff);
  $xnor = na_array_diff($xnor,$na_array_intersection);
  return array_values($xnor);
}

$array1=array(“3″,”1″,”2″,”3″,”a”,”3″,”b”,”3″,”5″);
$array2=array(“3″,”1″,”3″,”3″,”4″,”6”);
$array3=array(“3″,”1″,”2″,”4″,”7”);

echo(implode(“, “,na_array_xnor($array1,$array2,$array3)));

PRODUCES:

3, 3, 2, 4

Note that the only “3”s that are returned are those that are not in the intersection and not in the diff.

na_array_xor (...$arrays);
function na_array_xor(...$arrays){
  $xnor = array();
  $true_xnor = call_user_func_array('na_array_xnor',$arrays);
  $true_combination  = call_user_func_array('na_array_merge',$arrays);
  //// xor = combination - xnor
  $xor = na_array_diff($true_combination,$true_xnor);
  return array_values($xor);
}

$array1=array(“3″,”1″,”2″,”3″,”a”,”3″,”b”,”3″,”5″);
$array2=array(“3″,”1″,”3″,”3″,”4″,”6”);
$array3=array(“3″,”1″,”2″,”4″,”7”);

echo(implode(“, “,na_array_xor($array1,$array2,$array3)));

PRODUCES:

3, 3, 1, a, b, 5, 6, 7

Note that the only “3”s that are returned are those that are both in the intersection and in the diff.