21

我有一个数组

Array(
[0] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )

[1] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )

[2] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 8
        [frame_id] => 8
    )

[3] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )

[4] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )

)

如您所见,密钥 0 与 1、3 和 4 相同。密钥 2 与它们都不同。

在它们上运行 array_unique 函数时,唯一的左边是

Array (
[0] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )
)

任何想法为什么 array_unique 没有按预期工作?

4

7 回答 7

80

这是因为array_unique使用字符串比较来比较项目。从文档

注意:当且仅当 (string) $elem1 === (string) $elem2 时,才认为两个元素相等。换句话说:当字符串表示相同时。将使用第一个元素。

数组的字符串表示就是单词Array,不管它的内容是什么。

您可以使用以下命令执行您想要执行的操作:

$arr = array(
    array('user_id' => 33, 'frame_id' => 3),
    array('user_id' => 33, 'frame_id' => 3),
    array('user_id' => 33, 'frame_id' => 8)
);

$arr = array_intersect_key($arr, array_unique(array_map('serialize', $arr)));

//result:
array
  0 => 
    array
      'user_id' => int 33
      'user' => int 3
  2 => 
    array
      'user_id' => int 33
      'user' => int 8

以下是它的工作原理:

  1. 每个数组项都是序列化的。根据数组的内容,这将是唯一的。

  2. 这个结果是遍历的array_unique,所以只剩下具有唯一签名的数组。

  3. array_intersect_key将从 map/unique 函数中获取唯一项的键(因为保留了源数组的键)并将它们从原始源数组中拉出。

于 2010-04-01T14:53:49.933 回答
5

这是@ryeguy 答案的改进版本:

<?php

$arr = array(
    array('user_id' => 33, 'tmp_id' => 3),
    array('user_id' => 33, 'tmp_id' => 4),
    array('user_id' => 33, 'tmp_id' => 5)
);


# $arr = array_intersect_key($arr, array_unique(array_map('serialize', $arr)));
$arr = array_intersect_key($arr, array_unique(array_map(function ($el) {
    return $el['user_id'];
}, $arr)));

//result:
array
  0 => 
    array
      'user_id' => int 33
      'tmp_id' => int 3

首先,它不会进行不必要的序列化。其次,即使 id 相同,有时属性也可能不同。

这里的诀窍是array_unique()保留密钥:

$ php -r 'var_dump(array_unique([1, 2, 2, 3]));'
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [3]=>
  int(3)
}

这让我们array_intersect_key()留下所需的元素。

我用Google Places API遇到过它。我将几个请求的结果与不同类型的对象(想想标签)结合起来。但是我得到了重复,因为一个对象可能被分为几个类别(类型)。并且 with 的方法serialize不起作用,因为 attrs 不同,即photo_referencereference。可能这些就像临时ID。

于 2016-12-07T15:02:14.983 回答
3

array_unique()仅在 PHP 5.2.9 及更高版本中支持多维数组。

相反,您可以创建数组的哈希并检查它的唯一性。

$hashes = array(); 

foreach($array as $val) { 
    $hashes[md5(serialize($val))] = $val; 
} 

array_unique($hashes);
于 2010-04-01T14:56:44.040 回答
2

array_unique deos 不能递归工作,所以它只是认为“这都是Arrays,让我们杀死除一个之外的所有......我们开始吧!”

于 2010-04-01T14:54:38.547 回答
1

快速回答 (TL;DR)

  • 可以使用 foreach 从 PHP Array of AssociativeArrays 中提取不同的值
  • 这是一个简单的方法

详细解答

语境

  • PHP 5.3
  • PHP Array of AssociativeArrays(表格复合数据变量)
  • 此复合变量的替代名称是 ArrayOfDictionary (AOD)

问题

  • 场景: DeveloperMarsher 有一个 PHP 表格复合变量
    • DeveloperMarsher 希望提取特定名称-值对上的不同值
    • 在下面的示例中,DeveloperMarsher 希望为每个不同的fname名称-值对获取行

解决方案

  • 例子01;; DeveloperMarsher 以如下所示的表格数据变量开始

    $aodtable = json_decode('[
    {
      “fname”:“本垒打”
      "lname": "辛普森"
    },
    {
      “fname”:“本垒打”
      "lname": "杰克逊"
    },
    {
      “fname”:“本垒打”
      "lname": "约翰逊"
    },
    {
      “fname”:“巴特”
      "lname": "约翰逊"
    },
    {
      “fname”:“巴特”
      "lname": "杰克逊"
    },
    {
      “fname”:“巴特”
      "lname": "辛普森"
    },
    {
      “fname”:“弗雷德”
      "lname": "燧石"
    }
    ]',真的);
    
  • 例子01;; DeveloperMarsher 可以使用跟踪所见值的 foreach 循环提取不同的值

    $sgfield = 'fname';
    $bgnocase = 真;
    
    //
    $targfield = $sgfield;
    $ddseen = 数组();
    $vout = 数组();
    foreach ($aodtable as $datarow) {
    if( (boolean) $bgnocase == true ){ @$datarow[$targfield] = @strtolower($datarow[$targfield]); }
    if( (字符串) @$ddseen[ $datarow[$targfield] ] == '' ){
      $rowout = array_intersect_key($datarow, array_flip(array_keys($datarow)));
      $ddseen[ $datarow[$targfield] ] = $datarow[$targfield];
      $vout[] = 数组($rowout);
    }
    }
    //;;
    
    打印 var_export( $vout, true );
    

输出结果

大批 (
  0 =>
  大批 (
    0 =>
    大批 (
      'fname' => '本垒打',
      'lname' => '辛普森',
    ),
  ),
  1 =>
  大批 (
    0 =>
    大批 (
      'fname' => '巴特',
      'lname' => '约翰逊',
    ),
  ),
  2 =>
  大批 (
    0 =>
    大批 (
      'fname' => '弗雷德',
      'lname' => '燧石',
    ),
  ),
)

陷阱

  • 此解决方案不会聚合不属于 DISTINCT 操作的字段
  • 从任意选择的不同行返回任意名称-值对
  • 输出的任意排序顺序
  • 任意处理字母大小写(大写 A 与小写 a 不同吗?)

也可以看看

  • php array_intersect_key
  • php 数组翻转
于 2017-02-27T21:07:02.247 回答
1
function array_unique_recursive($array)
{
    $array = array_unique($array, SORT_REGULAR);

    foreach ($array as $key => $elem) {
        if (is_array($elem)) {
            $array[$key] = array_unique_recursive($elem);
        }
    }

    return $array;
}

这不是诀窍吗?

于 2018-11-08T12:30:38.063 回答
0
`

    $arr = array(
        array('user_id' => 33, 'tmp_id' => 3),
        array('user_id' => 33, 'tmp_id' => 4),
        array('user_id' => 33, 'tmp_id' => 3),
        array('user_id' => 33, 'tmp_id' => 4),
    );
    $arr1 = array_unique($arr,SORT_REGULAR);
    echo "<pre>";
    print_r($arr1);
    echo "</pre>";
   Array(   
        [0] => Array(
                    [user_id] => 33
                    [tmp_id] => 3
        )
        [1] => Array(
                     [user_id] => 33
                     [tmp_id] => 4
          )
        )
    

`
于 2021-06-04T11:59:16.013 回答