将三维数组合并为单个数组并删除重复值?

时间:2018-05-02 05:08:12

标签: php arrays sorting multidimensional-array

我在不同的数组中得到具有重复值的三维数组,我想将这个三维数组合并到一个数组中,并删除最终数组中的重复值。

我的数组是:

repo/public/index.html

我尝试了以下解决方案,但没有工作:

Array
(
[0] => Array
    (
        [0] => Array
            (
                [role_id] => 2
                [name] => name1
                [email] => email1@somemail.com
            )

        [1] => Array
            (
                [role_id] => 2
                [name] => name2
                [email] => email2@somemail.com
            )

        [2] => Array
            (
                [role_id] => 2
                [name] => name3 
                [email] => email3@somemail.com
            )
    )

[1] => Array
    (
        [0] => Array
            (
                [role_id] => 2
                [name] => name4
                [email] => email4@somemail.com
            )

        [1] => Array
            (
                [role_id] => 2
                [name] => name3 
                [email] => email3@somemail.com
            )
    )

[2] => Array
    (
        [0] => Array
            (
                [role_id] => 2
                [name] => name3 
                [email] => email3@somemail.com
            )

        [1] => Array
            (
                [role_id] => 2
                [name] => name2
                [email] => email2@somemail.com
            )
    )
[3] => Array
    (
        [0] => Array
            (
                [role_id] => 2
                [name] => name3 
                [email] => email3@somemail.com
            )
    )
)

我想将此数组合并为一个单维数组,并从中删除重复值。我可以通过循环遍历每个数组得到结果,但执行时间会更多,我希望必须有一些简单的解决方案。任何人都可以解决这个问题,谢谢。

2 个答案:

答案 0 :(得分:0)

请尝试此代码

$list = is your array;     
$flattern_array = array();
    $flat_array = function($item) use(&$flattern_array, &$flat_array){
          $keys = array_keys($item);
          if(is_array($item) && !in_array("role_id", $keys, TRUE)){
            foreach($item as $_item){
              $flat_array($_item);
            }
          }else{
              $flattern_array[] = $item;
          }
    };

    $flat_array($list);

   // Now $flattern_array have all items
   //Here we can remove duplicates from array
    $result = array_map("unserialize", array_unique(array_map("serialize", $flattern_array)));

答案 1 :(得分:0)

我们不是为这个数据集编写纯粹的自定义解决方案,而是首先创建一些通用函数,这样可以更方便地处理数据的一般术语

我们从flatten函数开始,该函数采用N维数组并返回N-1维数组。

function flatten (array $xs) {
  return array_reduce
    ( $xs
    , 'array_merge'
    , []
    )
  ;
}

var_export (flatten ($data));

// array (
//   0 => 
//     array ( 'role_id' => 2, 'name' => 'name1', 'email' => 'email1@somemail.com', ),
//   1 => 
//     array ( 'role_id' => 2, 'name' => 'name2', 'email' => 'email2@somemail.com', ),
//   2 => 
//     array ( 'role_id' => 2, 'name' => 'name3', 'email' => 'email3@somemail.com', ),
//   3 => 
//     array ( 'role_id' => 2, 'name' => 'name4', 'email' => 'email4@somemail.com', ),
//   4 => 
//     array ( 'role_id' => 2, 'name' => 'name3', 'email' => 'email3@somemail.com', ),
//   5 => 
//     array ( 'role_id' => 2, 'name' => 'name3', 'email' => 'email3@somemail.com', ),
//   6 => 
//     array ( 'role_id' => 2, 'name' => 'name2', 'email' => 'email2@somemail.com', ),
//   7 => 
//     array ( 'role_id' => 2, 'name' => 'name3', 'email' => 'email3@somemail.com', ),
// )

现在如果我们可以使用PHP的array_unique会很好,但它只适用于原始值。在这种情况下,我们需要一个允许我们指定更复杂的匹配行为的函数。为此,我们制作了自己的array_unique_by函数

function array_unique_by (array $xs, callable $f) {
  return array_reduce
    ( $xs
    , function ($acc, $x) use ($f) {
        if ( array_search_by ( $acc
                             , function ($y) use ($f, $x) {
                                 return call_user_func ($f, $x, $y);
                               }
                             )
             === null
           )
          return array_merge ($acc, [ $x ]);
        else
          return $acc;
      }
    , []
    )
  ;
}

在我们进一步发展之前,请注意我们已经介绍了array_search_by。与PHP的array_unique一样,PHP的array_search也适用于原始值,因此我们需要一种方法来搜索复杂的值,比如数据集中的值。

function array_search_by (array $xs, callable $f) {
  foreach ($xs as $x) {
    if (call_user_func($f, $x) === true)
      return $x;
  }
  return null;
}

最后,为了让我们使用array_unique_by函数,我们需要传递匹配函数。此函数将告诉array_unique_by我们数据集的哪些元素被视为“匹配”。例如,我们将此称为match_user,因为您的数据集中的元素看起来像是用户。

function match_user ($a, $b) {
  return $a["role_id"] === $b["role_id"]
    && $a["name"] === $b["name"]
    && $a["email"] === $b["email"]
  ;
}

一切就绪后,我们现在可以编写一个非常简单的程序来实现您想要的结果

var_export (array_unique_by (flatten ($data), 'match_user'));

// array (
//   0 => 
//   array ( 'role_id' => 2, 'name' => 'name1', 'email' => 'email1@somemail.com', ),
//   1 => 
//   array ( 'role_id' => 2, 'name' => 'name2', 'email' => 'email2@somemail.com', ),
//   2 => 
//   array ( 'role_id' => 2, 'name' => 'name3', 'email' => 'email3@somemail.com', ),
//   3 => 
//   array ( 'role_id' => 2, 'name' => 'name4', 'email' => 'email4@somemail.com', ),
// )

<强>备注

上述函数是用函数式编写的,在PHP中很难表达。我很难找到array_unique_by找到合适的语法格式。关键是,您可以根据需要实现这些通用功能。这是使用命令式样式的array_unique_by的另一种可能实现,这对PHP程序员来说更为熟悉。此实现与上面定义的版本完全相同,但可能更好地向读者传达其意图

function array_unique_by (array $xs, callable $f) {
  $acc = [];
  foreach ($xs as $x) {
    $match =
      array_search_by
        ( $acc
        , function ($y) use ($f, $x) {
            return call_user_func ($f, $x, $y);
          }
        )
      ;
    if ($match === null)
      array_push ($acc, $x);
  }
  return $acc;
}

最后,PHP anonymous functions的lambda语法也非常流行。为了利用在lambda之外定义的变量,我们必须使用这种笨拙的use ($f, $x)语法。我们可以使用其他通用帮助函数来解决这个问题,例如下面介绍的partial

function partial (callable $f, ...$xs) {
  return function (...$ys) use ($f, $xs) {
    return call_user_func_array
      ( $f
      , array_merge ($xs, $ys)
      )
    ;
  };
}

function array_unique_by (array $xs, callable $f) {
  $acc = [];
  foreach ($xs as $x) {
    $match =
      array_search_by
        ( $acc
        , partial ($f, $x)
        )
      ;
    if ($match === null)
      array_push ($acc, $x);
  }
  return $acc;
}

上面,array_unique_by与其他实现完全相同,但更容易阅读。你可以继续使用它直到你开心。

这里的想法很简单:你可以使用泛型函数创建缺失的特征或抽象出烦恼。然后可以以各种优雅的方式组合这些功能,从而使读者更容易理解的程序。

<强>性能

我们的array_unique_by函数使用我们自己的array_search_by函数。如果我们在心理上可视化正在进行的过程,我们输入中的每个元素都需要与我们正在构建的输出$acc进行比较。我们在这里进行的“找到匹配”是通过在$acc的开头搜索并逐个查看每个元素来完成的,直到找到潜​​在的匹配...

如果我们的输入数据非常大,则此linear search的性能配置文件非常糟糕。优化此方法的一种方法是将$acc改为binary search tree。但当然这意味着我们必须创建一个适合我们数据集的。或许我们可以利用PHP的hashable接口来减少工作量。这样的实现受益于二进制搜索,它比线性搜索快得多。

本练习留待读者阅读。