Значения массива php-фильтра и удаление дубликатов из многомерного массива

Привет всем, я пытаюсь найти дубликаты значений х из этого массива и удалить их и оставить только уникальные. Например, мой массив

Array
(
[0] => Array
    (
        [x] => 0.5
        [y] => 23
    )

[1] => Array
    (
        [x] => 23
        [y] => 21.75
    )

[2] => Array
    (
        [x] => 14.25
        [y] => 21.875
    )

[3] => Array
    (
        [x] => 19.375
        [y] => 21.75
    )

[4] => Array
    (
        [x] => 9.125
        [y] => 21.875
    )

[5] => Array
    (
        [x] => 23
        [y] => 19.625
    )

[6] => Array
    (
        [x] => 19.375
        [y] => 19.625
    ) 
)

Итак, что мне нужно сделать, так это пройтись по всему циклу и увидеть первое значение x как.5, затем продолжить, а все остальное, имеющее x как.5, удалить его из массива, чтобы в конце я получил массив, который выглядит следующим образом

 Array
   (
[0] => Array
    (
        [x] => 0.5
        [y] => 23
    )

[1] => Array
    (
        [x] => 23
        [y] => 21.75
    )

[2] => Array
    (
        [x] => 14.25
        [y] => 21.875
    )

[3] => Array
    (
        [x] => 19.375
        [y] => 21.75
    )

[4] => Array
    (
        [x] => 9.125
        [y] => 21.875
    )
)

где все значения X являются уникальными. Я искал в Интернете и обнаружил, что эта функция используется, но, похоже, она не работает:

 $result = array_map("unserialize", array_unique(array_map("serialize", $array)));    

5 ответов

Решение

Просто переберите и найдите уникальные значения, как вы идете:

$taken = array();

foreach($items as $key => $item) {
    if(!in_array($item['x'], $taken)) {
        $taken[] = $item['x'];
    } else {
        unset($items[$key]);
    }
}

Каждый первый раз x Значение используется, мы сохраняем его - и последующие использования unset из массива.

Опаздывать на вечеринку: обязательная острота.

      $out = array_values ( array_intersect_key( $in, array_unique( array_column( $in, 'x' ) ) ) );

И шаг за шагом (на моем собственном примере):

      $in = [
    [ 'k' => 'a' ],
    [ 'k' => 'a' ],
    [ 'k' => 'b' ]
];

print_r( array_column( $in, 'k' ) );

array_columnвозвращает плоский массив только со значениями всех k-ключей:

      Array
(
    [0] => a
    [1] => a
    [2] => b
)

Теперь мы можем отфильтровать это с помощьюarray_unique:

      print_r( array_unique( array_column( $in, 'k' ) ) ) );

Получить:

      Array
(
    [0] => a
    [2] => b
)

Видите, что мы сохранили ключи исходного массива (0 и 2)? Мы можем использовать это сarray_intersect_key. Он вычисляет пересечение массивов, используя ключи для сравнения.

      print_r( array_intersect_key( $in, array_unique( array_column( $in, 'k' ) ) ) );

Мы получаем первый[0]и третий[2]запись нашего исходного массива.

      Array
(
    [0] => Array
        (
            [k] => a
        )

    [2] => Array
        (
            [k] => b
        )

)

Теперь ключи перепутаны (что может привести к проблемам, если циклы for), поэтому мы заворачиваем все это вarray_values:

      print_r(
  array_values( array_intersect_key( $in, array_unique( array_column( $in, 'k' ) ) ) ) 
);
      Array
(
    [0] => Array
        (
            [k] => a
        )

    [1] => Array
        (
            [k] => b
        )

)

Этот вопрос дублирует этот, кстати.

array_unique сравнивает строковые значения, так что вы можете создавать объекты (с перегруженным __toString функция) в качестве промежуточного шага.

class XKeyObj {
    public $x;
    public $y;

    public function XKeyObj($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }

    public function __toString() { return strval($this->x); }
}

function array_to_xKey($arr) { return new XKeyObj($arr['x'], $arr['y']); }
function xKey_to_array($obj) { return array('x' => $obj->x, 'y' => $obj->y); }

$input = array(
    array('x' => 0.5, 'y' => 23),
    array('x' => 23, 'y' => 21.75),
    array('x' => 14.25, 'y' => 21.875),
    array('x' => 19.375, 'y' => 21.75),
    array('x' => 9.125, 'y' => 21.875),
    array('x' => 23, 'y' => 19.625),
    array('x' => 19.375, 'y' => 19.625)
);

$output = array_map('xKey_to_array',
                    array_unique(array_map('array_to_xKey', $input)));

print_r($output);

Результат:

Array
(
    [0] => Array
        (
            [x] => 0.5
            [y] => 23
        )

    [1] => Array
        (
            [x] => 23
            [y] => 21.75
        )

    [2] => Array
        (
            [x] => 14.25
            [y] => 21.875
        )

    [3] => Array
        (
            [x] => 19.375
            [y] => 21.75
        )

    [4] => Array
        (
            [x] => 9.125
            [y] => 21.875
        )

)

При выполнении повторяющихся проверок массивов производительность перетаскивается на in_array() будет постепенно ухудшаться по мере увеличения размера вашего временного массива поиска.

Имея это в виду, используйте временные ассоциативные ключи для идентификации последующих дубликатов, чтобы !isset()может быть вызван для растущей переменной результата. Поскольку массивы php представляют собой хэш-карты, этот метод будет неизменно превосходитьin_array().

Есть ловушка с этими временными ключами, которая относится конкретно к вашим значениям типа float. Когда в качестве ключей массива используются числа с плавающей запятой, php преобразует их в целые числа путем усечения ("пол", а не "округление"). Чтобы избежать этого нежелательного побочного эффекта, добавьте к временным клавишам нечисловой символ (кроме дефиса, конечно), чтобы число с плавающей запятой стало строкой.

Код: (Демо)

$array = [
    ['x' => 0.5, 'y' => 23],
    ['x' => 23, 'y' => 21.75],
    ['x' => 14.25, 'y' => 21.875],
    ['x' => 19.375, 'y' => 21.75],
    ['x' => 9.125, 'y' => 21.875], 
    ['x' => 23, 'y' => 19.625],
    ['x' => 19.375, 'y' => 19.625],
];

foreach ($array as $row) {
    if (!isset($result['#' . $row['y']])) {
        $result['#' . $row['y']] = $row;
    }
}
var_export(array_values($result));

Выход:

array (
  0 => 
  array (
    'x' => 0.5,
    'y' => 23,
  ),
  1 => 
  array (
    'x' => 23,
    'y' => 21.75,
  ),
  2 => 
  array (
    'x' => 14.25,
    'y' => 21.875,
  ),
  3 => 
  array (
    'x' => 23,
    'y' => 19.625,
  ),
)

ps При работе со строковыми или целочисленными значениями как временными ключами нет необходимости добавлять какие-либо символы. Если вы не заботитесь об удалении временных ключей из результата (потому что вы обращаетесь только к значениям подмассива "down script", то вам не нужно вызыватьarray_values() после итерации.

array_unique(my_array, SORT_REGULAR)
Другие вопросы по тегам