Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

What I've been working on is some kind of function that can take basically any well constructed multi-dimensional array and remove any and all duplicates within matching key sets.

The particular function I've designed provides convenience and functionality but it is far from pretty and seemingly slow compared to a possibly more optimized function.

Sample Data

$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two']['level-three'][] = '1';
$echo['level-one']['level-two']['level-three'][] = '2';
$echo['level-one']['level-two']['level-three'][] = '3';
$echo['level-one']['level-two']['level-three'][] = '4';

Function Declaration and Execution

function array_unique_multidimensional($name=null,$tv=null,$tk=null,$ta=null){

  if(!isset($ta)){$ta = ''.$name.'';}else{$ta .= '['.$tk.']';}

  if(!isset($tv)){$tv = '$v';}else{$tv .= 'v';}

  if(!isset($tk)){$tk = '$k';}else{$tk .= 'k';}

  return('
    foreach('.$ta.' as '.$tk.' => '.$tv.'){

      if(is_array('.$tv.')){
        eval(array_unique_multidimensional(\'\',\''.$tv.'\',\''.$tk.'\',\''.$ta.'\'));
      }else{
        '.$ta.' = array_unique('.$ta.');
      }

     }
  '); //end return

}

eval(array_unique_multidimensional('$echo'));
//Yes this function returns a foreach loop so it must be eval'd
//then it recursively calls itself until the entire array is traversed
//This will ensure every segment of the array is unique individually

Alright so I spaced it out a lot more then it probably needs to be and it is probably best viewed in some kind of program editor. Anyway after running the script as it is shown above you should get level's one and two reduced to a single entry and level three should have all four of it's entries (since their values are unique and one and two's are not).

I've seen a lot of answers using array_map to serialize and unique but I've found that they do not work for multidimensional arrays of varying calibers. Ultimately this function will accept any size and depth of array, compare every single key set to itself, remove any duplicates, and preserve every array name/key contained within.

Does anyone know of a better way to go about this? If not enjoy the working code above, if you do please share :)

share|improve this question
I'd only add that your variables are not very descriptive (ta, tv, tk), which makes reading the function difficult at places. And also that eval() is evil. I'd use either of the other two functions before this one just for that alone. – mseancole Jul 5 '12 at 14:12

migrated from stackoverflow.com Jul 5 '12 at 10:04

2 Answers

Shortest solution I can come up with:

function array_unique_recursive ($array) {

    // First loop the array and call self on any sub arrays
    // Note that $value is referenced
    foreach ($array as &$value) {
        if (is_array($value)) {
            $value = array_unique_recursive($value);
        }
    }

    // Now unique this level
    return array_unique($array, SORT_REGULAR);

}

print_r(array_unique_recursive($echo));

See it working

share|improve this answer

This is probably better than using eval. This solution touches only keys which are numeric, leaving string keys unchanged:

<?php

$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two'][] = '1';
$echo['level-one']['level-two']['level-three'][] = '1';
$echo['level-one']['level-two']['level-three'][] = '2';
$echo['level-one']['level-two']['level-three'][] = '3';
$echo['level-one']['level-two']['level-three'][] = '4';

function makeUnique(array $arr) {
  $seen = array();
  foreach (array_keys($arr) as $key) {
    if (is_array($arr[$key])) {
      $arr[$key] = makeUnique($arr[$key]);
    } else {
      if (is_numeric($key)) {
        $v = (string)$arr[$key];
        if (isset($seen[$v])) {
          unset($arr[$key]);
        } else {
          $seen[$v] = true;
        }
      }
    }
  }
  return $arr;
}

print_r(makeUnique($echo));
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.