如何在数组数组上使用array_unique?

时间:2022-10-25 09:57:11

I have an array

我有一个阵列

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
    )

)

As you can see key 0 is the same as 1,3 and 4. And key 2 is different from them all.

正如您所看到的,键0与1,3和4相同。键2与它们都不同。

When running the array_unique function on them, the only left is

当对它们运行array_unique函数时,唯一的左边是

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

)

any ideas why array_unique isn't working as expected?

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

5 个解决方案

#1


59  

It's because array_unique compares items using a string comparison. From the docs:

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

Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.

注意:当且仅当(字符串)$ elem1 ===(字符串)$ elem2时,两个元素被认为是相等的。用文字表示:当字符串表示相同时。将使用第一个元素。

The string representation of an array is simply the word Array, no matter what its contents are.

无论内容是什么,数组的字符串表示只是单词Array。

You can do what you want to do by using the following:

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

$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

Here's how it works:

以下是它的工作原理:

  1. Each array item is serialized. This will be unique based on the array's contents.

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

  2. The results of this are run through array_unique, so only arrays with unique signatures are left.

    其结果通过array_unique运行,因此只剩下具有唯一签名的数组。

  3. array_intersect_key will take the keys of the unique items from the map/unique function (since the source array's keys are preserved) and pull them out of your original source array.

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

#2


3  

array_unique() only supports multi-dimensional arrays in PHP 5.2.9 and higher.

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

Instead, you can create a hash of the array and check it for unique-ness.

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

$hashes = array(); 

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

array_unique($hashes);

#3


2  

Here's an improved version of @ryeguy's answer:

这是@ 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

First, it doesn't do unneeded serialization. Second, sometimes attributes may be different even so id is the same.

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

I've run into it with Google Places API. I was combining results of several requests with different type of objects (think tags). But I got duplicates, since an object may be put into several categories (types). And the method with serialize didn't work, since the attrs were different, namely, photo_reference and reference. Probably these are like temporary ids.

我使用Google Places API遇到了它。我将几个请求的结果与不同类型的对象(思考标签)结合起来。但我得到了重复,因为一个对象可能被分成几个类别(类型)。并且序列化的方法不起作用,因为attrs是不同的,即photo_reference和reference。可能这些就像临时的ids。

#4


1  

array_unique deosn't work recursive, so it just thinks "this are all Arrays, let's kill all but one... here we go!"

array_unique deos不起作用递归,所以它只是认为“这是所有阵列,让我们杀掉除了一个......我们走了!”

#5


0  

Quick Answer (TL;DR)

  • Distinct values may be extracted from PHP Array of AssociativeArrays using foreach
  • 可以使用foreach从PHP Array of AssociativeArrays中提取不同的值
  • This is a simplistic approach
  • 这是一种简单的方法

Detailed Answer

Context

  • PHP 5.3
  • PHP 5.3
  • PHP Array of AssociativeArrays (tabluar composite data variable)
  • PHP的AssociativeArrays数组(tabluar复合数据变量)
  • Alternate name for this composite variable is ArrayOfDictionary (AOD)
  • 此复合变量的备用名称是ArrayOfDictionary(AOD)

Problem

  • Scenario: DeveloperMarsher has a PHP tabular composite variable
    • DeveloperMarsher wishes to extract distinct values on a specific name-value pair
    • DeveloperMarsher希望在特定的名称 - 值对上提取不同的值
    • In the example below, DeveloperMarsher wishes to get rows for each distinct fname name-value pair
    • 在下面的示例中,DeveloperMarsher希望为每个不同的fname名称 - 值对获取行
  • 场景:DeveloperMarsher有一个PHP表格复合变量DeveloperMarsher希望在特定的名称 - 值对上提取不同的值在下面的示例中,DeveloperMarsher希望为每个不同的fname名称 - 值对获取行

Solution

  • example01 ;; DeveloperMarsher starts with a tabluar data variable that looks like this

    example01 ;; DeveloperMarsher以一个看起来像这样的tabluar数据变量开始

    $aodtable = json_decode('[
    {
      "fname": "homer"
      ,"lname": "simpson"
    },
    {
      "fname": "homer"
      ,"lname": "jackson"
    },
    {
      "fname": "homer"
      ,"lname": "johnson"
    },
    {
      "fname": "bart"
      ,"lname": "johnson"
    },
    {
      "fname": "bart"
      ,"lname": "jackson"
    },
    {
      "fname": "bart"
      ,"lname": "simpson"
    },
    {
      "fname": "fred"
      ,"lname": "flintstone"
    }
    ]',true);
    
  • example01 ;; DeveloperMarsher can extract distinct values with a foreach loop that tracks seen values

    example01 ;; DeveloperMarsher可以使用跟踪看到的值的foreach循环提取不同的值

    $sgfield  =   'fname';
    $bgnocase =   true;
    
    //
    $targfield  =   $sgfield;
    $ddseen     =   Array();
    $vout       =   Array();
    foreach ($aodtable as $datarow) {
    if( (boolean) $bgnocase == true ){ @$datarow[$targfield] = @strtolower($datarow[$targfield]); }
    if( (string) @$ddseen[ $datarow[$targfield] ] == '' ){
      $rowout   = array_intersect_key($datarow, array_flip(array_keys($datarow)));
      $ddseen[ $datarow[$targfield] ] = $datarow[$targfield];
      $vout[] = Array( $rowout );
    }
    }
    //;;
    
    print var_export( $vout, true );
    

Output result

array (
  0 =>
  array (
    0 =>
    array (
      'fname' => 'homer',
      'lname' => 'simpson',
    ),
  ),
  1 =>
  array (
    0 =>
    array (
      'fname' => 'bart',
      'lname' => 'johnson',
    ),
  ),
  2 =>
  array (
    0 =>
    array (
      'fname' => 'fred',
      'lname' => 'flintstone',
    ),
  ),
)

Pitfalls

  • This solution does not aggregate on fields that are not part of the DISTINCT operation
  • 此解决方案不会聚合在不属于DISTINCT操作的字段上
  • Arbitrary name-value pairs are returned from arbitrarily chosen distinct rows
  • 从任意选择的不同行返回任意名称 - 值对
  • Arbitrary sort order of output
  • 任意排序顺序的输出
  • Arbitrary handling of letter-case (is capital A distinct from lower-case a ?)
  • 字母案件的任意处理(资本A与小写字母a不同?)

See also

  • php array_intersect_key
  • php array_intersect_key
  • php array_flip
  • php array_flip

#1


59  

It's because array_unique compares items using a string comparison. From the docs:

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

Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.

注意:当且仅当(字符串)$ elem1 ===(字符串)$ elem2时,两个元素被认为是相等的。用文字表示:当字符串表示相同时。将使用第一个元素。

The string representation of an array is simply the word Array, no matter what its contents are.

无论内容是什么,数组的字符串表示只是单词Array。

You can do what you want to do by using the following:

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

$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

Here's how it works:

以下是它的工作原理:

  1. Each array item is serialized. This will be unique based on the array's contents.

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

  2. The results of this are run through array_unique, so only arrays with unique signatures are left.

    其结果通过array_unique运行,因此只剩下具有唯一签名的数组。

  3. array_intersect_key will take the keys of the unique items from the map/unique function (since the source array's keys are preserved) and pull them out of your original source array.

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

#2


3  

array_unique() only supports multi-dimensional arrays in PHP 5.2.9 and higher.

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

Instead, you can create a hash of the array and check it for unique-ness.

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

$hashes = array(); 

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

array_unique($hashes);

#3


2  

Here's an improved version of @ryeguy's answer:

这是@ 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

First, it doesn't do unneeded serialization. Second, sometimes attributes may be different even so id is the same.

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

I've run into it with Google Places API. I was combining results of several requests with different type of objects (think tags). But I got duplicates, since an object may be put into several categories (types). And the method with serialize didn't work, since the attrs were different, namely, photo_reference and reference. Probably these are like temporary ids.

我使用Google Places API遇到了它。我将几个请求的结果与不同类型的对象(思考标签)结合起来。但我得到了重复,因为一个对象可能被分成几个类别(类型)。并且序列化的方法不起作用,因为attrs是不同的,即photo_reference和reference。可能这些就像临时的ids。

#4


1  

array_unique deosn't work recursive, so it just thinks "this are all Arrays, let's kill all but one... here we go!"

array_unique deos不起作用递归,所以它只是认为“这是所有阵列,让我们杀掉除了一个......我们走了!”

#5


0  

Quick Answer (TL;DR)

  • Distinct values may be extracted from PHP Array of AssociativeArrays using foreach
  • 可以使用foreach从PHP Array of AssociativeArrays中提取不同的值
  • This is a simplistic approach
  • 这是一种简单的方法

Detailed Answer

Context

  • PHP 5.3
  • PHP 5.3
  • PHP Array of AssociativeArrays (tabluar composite data variable)
  • PHP的AssociativeArrays数组(tabluar复合数据变量)
  • Alternate name for this composite variable is ArrayOfDictionary (AOD)
  • 此复合变量的备用名称是ArrayOfDictionary(AOD)

Problem

  • Scenario: DeveloperMarsher has a PHP tabular composite variable
    • DeveloperMarsher wishes to extract distinct values on a specific name-value pair
    • DeveloperMarsher希望在特定的名称 - 值对上提取不同的值
    • In the example below, DeveloperMarsher wishes to get rows for each distinct fname name-value pair
    • 在下面的示例中,DeveloperMarsher希望为每个不同的fname名称 - 值对获取行
  • 场景:DeveloperMarsher有一个PHP表格复合变量DeveloperMarsher希望在特定的名称 - 值对上提取不同的值在下面的示例中,DeveloperMarsher希望为每个不同的fname名称 - 值对获取行

Solution

  • example01 ;; DeveloperMarsher starts with a tabluar data variable that looks like this

    example01 ;; DeveloperMarsher以一个看起来像这样的tabluar数据变量开始

    $aodtable = json_decode('[
    {
      "fname": "homer"
      ,"lname": "simpson"
    },
    {
      "fname": "homer"
      ,"lname": "jackson"
    },
    {
      "fname": "homer"
      ,"lname": "johnson"
    },
    {
      "fname": "bart"
      ,"lname": "johnson"
    },
    {
      "fname": "bart"
      ,"lname": "jackson"
    },
    {
      "fname": "bart"
      ,"lname": "simpson"
    },
    {
      "fname": "fred"
      ,"lname": "flintstone"
    }
    ]',true);
    
  • example01 ;; DeveloperMarsher can extract distinct values with a foreach loop that tracks seen values

    example01 ;; DeveloperMarsher可以使用跟踪看到的值的foreach循环提取不同的值

    $sgfield  =   'fname';
    $bgnocase =   true;
    
    //
    $targfield  =   $sgfield;
    $ddseen     =   Array();
    $vout       =   Array();
    foreach ($aodtable as $datarow) {
    if( (boolean) $bgnocase == true ){ @$datarow[$targfield] = @strtolower($datarow[$targfield]); }
    if( (string) @$ddseen[ $datarow[$targfield] ] == '' ){
      $rowout   = array_intersect_key($datarow, array_flip(array_keys($datarow)));
      $ddseen[ $datarow[$targfield] ] = $datarow[$targfield];
      $vout[] = Array( $rowout );
    }
    }
    //;;
    
    print var_export( $vout, true );
    

Output result

array (
  0 =>
  array (
    0 =>
    array (
      'fname' => 'homer',
      'lname' => 'simpson',
    ),
  ),
  1 =>
  array (
    0 =>
    array (
      'fname' => 'bart',
      'lname' => 'johnson',
    ),
  ),
  2 =>
  array (
    0 =>
    array (
      'fname' => 'fred',
      'lname' => 'flintstone',
    ),
  ),
)

Pitfalls

  • This solution does not aggregate on fields that are not part of the DISTINCT operation
  • 此解决方案不会聚合在不属于DISTINCT操作的字段上
  • Arbitrary name-value pairs are returned from arbitrarily chosen distinct rows
  • 从任意选择的不同行返回任意名称 - 值对
  • Arbitrary sort order of output
  • 任意排序顺序的输出
  • Arbitrary handling of letter-case (is capital A distinct from lower-case a ?)
  • 字母案件的任意处理(资本A与小写字母a不同?)

See also

  • php array_intersect_key
  • php array_intersect_key
  • php array_flip
  • php array_flip