【问题标题】:Remove duplicate pair of values in an array删除数组中重复的一对值
【发布时间】:2021-05-20 13:33:05
【问题描述】:

我有一个结构如下的数组:

[0] => Array
    (
        [venue1] => 1
        [venue2] => 2
    )

[1] => Array
    (
        [venue1] => 3
        [venue2] => 4
    )

[2] => Array
    (
        [venue1] => 2
        [venue2] => 1
    )

[3] => Array
    (
        [venue1] => 5
        [venue2] => 6
    )

我需要删除重复的“值对”,在本例中为第 [0] 行和第 [2] 行

我用那个代码试过了,但它不起作用(当然它不是很优雅);-)

foreach ( $compare_arr as $v1 ) 
{
    $key = array_search( intval($v1[venue1]), array_column( $compare_arr, 'venue2' ) );
    if ( $key <> '' ) unset($compare_arr[$key]);
}   

你知道如何解决这个问题吗?

非常感谢您的帮助! 奥利弗

【问题讨论】:

  • 我没有看到重复,你是什么意思?
  • 当您遇到困难时,我们很乐意提供帮助,但您仍需要努力。你试过什么吗?如果是这样,请分享您的努力并描述您在哪里以及如何未能实现您的需求。 @Progrock "pair of values""in this case row [0] and row [2]" 暗示删除值对,无论它们位于什么键下.
  • [0] 和 [2] 的 值相同(1+2 和 2+1)
  • 我添加了我当前的方法以获得可能的解决方案。也许有人知道为什么它不起作用或更优雅的解决方案。

标签: php arrays duplicates


【解决方案1】:

这是一种方法,其中中间数组由排序值组成。然后您可以搜索以找到要删除的重复对。

<?php

$venues = 
array (
    0 => 
    array (
      'venue1' => 1,
      'venue2' => 2,
    ),
    1 => 
    array (
      'venue1' => 3,
      'venue2' => 4,
    ),
    2 => 
    array (
      'venue1' => 2,
      'venue2' => 1,
    ),
    3 => 
    array (
      'venue1' => 5,
      'venue2' => 6,
    ),
);

$result = $pairs = $venues;
array_walk($pairs, 'sort');

var_export($pairs);

foreach($pairs as $k => $pair) {
    if(count(array_keys($pairs, $pair)) > 1) {
        unset($result[$k]);
    }
}

var_export($result); 

输出:

array (
    0 => 
    array (
      0 => 1,
      1 => 2,
    ),
    1 => 
    array (
      0 => 3,
      1 => 4,
    ),
    2 => 
    array (
      0 => 1,
      1 => 2,
    ),
    3 => 
    array (
      0 => 5,
      1 => 6,
    ),
  )array (
    1 => 
    array (
      'venue1' => 3,
      'venue2' => 4,
    ),
    3 => 
    array (
      'venue1' => 5,
      'venue2' => 6,
    ),
  )

如果您想删除出现的重复项而不是完全删除重复项,您可以对上面的排序数组执行 array_unique,然后使用剩余的键过滤原始数组。

$tmp     = $venues;
array_walk($tmp, 'sort');
$tmp     = array_unique($tmp, SORT_REGULAR);
$result  = array_intersect_key($venues, $tmp);
var_export($result);

输出:

array (
    0 => 
    array (
      'venue1' => 1,
      'venue2' => 2,
    ),
    1 => 
    array (
      'venue1' => 3,
      'venue2' => 4,
    ),
    3 => 
    array (
      'venue1' => 5,
      'venue2' => 6,
    ),
  )

【讨论】:

  • 非常感谢!这看起来非常好! :-) 是否可以不完全删除 both 重复对,而是让 one 保留? (因此结果是一个具有 1/2、3/4 和 5/6 的数组)
  • @o.heinrich 您可以使用 array_unique 在上面的中间数组上获得唯一的出现,并使用它来过滤原始数组。添加了一个示例。
【解决方案2】:

您也可以先循环数组,根据有序键创建复合键。

然后您可以过滤结果,仅保留计数为 2 的数组,因为没有重复项,因此不添加任何内容。

例如

$result = [];
$compare_arr = [
    ["venue1" => 1, "venue2" => 2],
    ["venue1" => 3, "venue2" => 4],
    ["venue1" => 2, "venue2" => 1],
    ["venue1" => 5, "venue2" => 6],
];

foreach ($compare_arr as $v1) {
    sort($v1);
    $cKey = $v1[0] .'-'. $v1[1];
    if (array_key_exists($cKey, $result)) {
        $result[$cKey][] = $v1;
        continue;
    }
    $result[$cKey] = $v1;
}
$result = array_filter($result, function($item) {
    return count($item) === 2;
});

print_r($result);

输出

Array
(
    [3-4] => Array
        (
            [0] => 3
            [1] => 4
        )

    [5-6] => Array
        (
            [0] => 5
            [1] => 6
        )

)

您可以看到复合键是介于两者之间的 - 的值。如果你想让键从 0 开始编号,你可以使用array_values

Php demo

编辑

如果您想保留第一个匹配的单对,您可以检查复合键,如果它已经存在,则继续循环而不覆盖现有的。

$result = [];
$compare_arr = [
    ["venue1" => 1, "venue2" => 2],
    ["venue1" => 3, "venue2" => 4],
    ["venue1" => 2, "venue2" => 1],
    ["venue1" => 5, "venue2" => 6]
];

foreach ($compare_arr as $v1) {
    sort($v1);
    $cKey = $v1[0] .'-'. $v1[1];
    if (array_key_exists($cKey, $result)) {
        continue;
    }
    $result[$cKey] = $v1;
}

print_r($result);

输出

Array
(
    [1-2] => Array
        (
            [0] => 1
            [1] => 2
        )

    [3-4] => Array
        (
            [0] => 3
            [1] => 4
        )

    [5-6] => Array
        (
            [0] => 5
            [1] => 6
        )

)

Php demo

【讨论】:

  • 这也是一个很好的解决方案! :-) 如何修改它以保留其中一个重复的对? (因此需要一个 1/2、3/4 和 5/6 的数组)
  • @o.heinrich 我为该场景添加了另一个示例。
  • 太棒了!这就是我要找的!太感谢了!你让我今天一整天都感觉很好! :-)))
  • @o.heinrich 如果通过单击此答案左侧的 ✓ 有助于解决您的问题,请随时 mark the answer 接受。请注意,您会得到 2 reputation points 接受解决方案。从 15 个声望点中,您可以upvote) 给出您认为有用的答案。
【解决方案3】:

无论您使用经典的foreach() 循环还是函数式迭代,都没有理由对输入数组进行多次迭代。

这个 sn-p 看起来与 TheFourthBird 的答案几乎相同,但我不喜欢不必要地使用 continue。这个 sn-p 将确保结果数组中的行没有 100% 共享场所值(以任何顺序)。子数组键也不会重新排序;换句话说,第一个元素键将是venue1,然后第二个元素将是venue2。使用implode() 提供了额外的灵活性,因为如果每行中的元素数量发生变化,则无需更改代码。

$result = [];
foreach ($data as $index => $row) {
    sort($row);
    $key = implode('-', $row);
    if (!isset($result[$key])) {
        $result[$key] = $data[$index];
    }
}
var_export(array_values($result));

输出:

array (
  0 => 
  array (
    'venue1' => 1,
    'venue2' => 2,
  ),
  1 => 
  array (
    'venue1' => 3,
    'venue2' => 4,
  ),
  2 => 
  array (
    'venue1' => 5,
    'venue2' => 6,
  ),
)

要完全删除共享场地值的所有行,请维护一个“找到”数组以及一个“结果”数组。

代码:(Demo)

$result = [];
foreach ($data as $index => $row) {
    sort($row);
    $key = implode('-', $row);
    if (!isset($found[$key])) {
        $found[$key] = true;
        $result[$key] = $data[$index];
    } else {
        unset($result[$key]);
    }
}
var_export(array_values($result));

输出:

array (
  0 => 
  array (
    'venue1' => 3,
    'venue2' => 4,
  ),
  1 => 
  array (
    'venue1' => 5,
    'venue2' => 6,
  ),
)

【讨论】:

    猜你喜欢
    • 2021-08-26
    • 2017-08-11
    • 2018-01-08
    • 2016-11-07
    • 2014-09-25
    • 2020-11-29
    • 2019-10-19
    • 2021-09-30
    • 2014-10-10
    相关资源
    最近更新 更多