Значения массива 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()
после итерации.