Я создаю форму с помощью цикла, выводящего значения внутри некоторых текстовых полей. Мне нужно проверить, есть ли повторяющиеся значения. Я думаю, мне нужно также поместить значения в массив и проверять их на каждом выходе.
$duplicates = array();
$has_duplicate = false;
foreach ($vals AS $v) {
if (in_array($v->val, $duplicates)) {
$has_duplicate = true;
}
echo '<input type = "text" value = "'.$v->val.'" class = "'.($has_duplicate ? 'dupe' : '').'">';
$duplicates[$v->val] = true;
}
Что-то вроде этого?
Вы можете использовать count(array_unique(array_column($vals, 'val')))
. Если это то же самое, что и count($vals)
, то дубликатов нет.
Какой у Вас вопрос?
Да что-то подобное. И собственно сам код.
Если вы собираетесь сделать это таким образом, вы должны установить цикл $has_duplicate = false;
внутри. В противном случае он сохранит свое значение true
из предыдущей итерации.
Обратите внимание, что эта форма array_column
будет работать только в PHP 7. В PHP 5 она может использоваться только для массивов массивов, но не для массивов объектов.
@ Don'tPanic Если найден дубликат, дубликаты всегда есть.
@Barmar он пометит следующее значение в $vals
как $has_duplicate
, даже если у этого значения нет дубликата. Переключатель $has_duplicate
никогда не выключается.
ОП поднимает флаг. Не обращайте внимания на имена переменных. Все значения должны иметь соответствующий key
в $duplicates
. Даже ответ ниже неверен. Код хорошо работает для OP.
Я имею в виду, что $has_duplicate
выглядит не так, как будто он должен применяться ко всему набору, а к конкретному значению, поскольку он определяет класс на входе для этого значения.
@ Don'tPanic Я не заметил, что он использовал переменную в операторе echo
, я подумал, что это просто глобальный флаг, сообщающий, были ли найдены какие-либо дубликаты.
Собственно проблему вижу:
foreach ($vals AS $v) {
if (in_array($v->val, $duplicates)) {
$has_duplicate = true;
}
$duplicates[$v->val] = true;
Вам нужно проверить isset
например:
foreach ($vals AS $v) {
$has_duplicate = false; //reset on each iteration of the loop
if (isset($duplicates[$v->val])) {
$has_duplicate = true;
}
....
Проблема в том, что in_array
смотрит в values
, и вы устанавливаете все значения на true
, вам нужно проверить ключи ($duplicates[$v->val] = true;
), в которые вы помещаете свои данные.
Вы также можете использовать array_key_exists()
для проверки, но этим никто не пользуется, так как он медленнее, чем isset.
in_array — Checks if a value exists in an array
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
http://php.net/manual/en/function.in-array.php
То, что я делал больше раз, чем хочу признаться.
ОБНОВИТЬ
Лучший способ написать это - просто покончить с локальной переменной, поскольку она на самом деле не нужна (если нет других мест, где она используется, не включенных в вопрос)
foreach ($vals AS $v) {
echo '<input type = "text" value = "'.$v->val.'" class = "'.(isset($duplicates[$v->val]) ? 'dupe' : '').'">';
$duplicates[$v->val] = true;
}
На самом деле нет никакой разницы, если вы установите это $duplicates[$v->val] = true;
несколько раз как True is True.
Ваше здоровье!
Как упоминалось в комментариях, вам нужно сбрасывать $has_duplicate
каждый раз в цикле, а не сохранять его значение с предыдущей итерации. Итак, вы можете просто сделать:
$has_duplicate = isset($duplicates[$v->val]);
Я думаю, если вы хотите пометить все значения, у которых есть дубликаты, вам нужно дважды повторить $vals
. В противном случае первый экземпляр значения, который появляется несколько раз, не будет помечен как дубликат, потому что нельзя определить, что он дублирован, пока это значение не встретится снова.
foreach ($vals as $v) {
if (isset($unique[$v->val])) $duplicates[$v->val] = true;
$unique[$v->val] = true;
}
foreach ($vals as $v) {
$class = isset($duplicate[$v->val]) ? 'dupe' : '';
echo '<input type = "text" value = "'. $v->val .'" class = "'. $class .'">';
}
Если вы хотите пометить только последующие экземпляры значения с помощью класса dupe
, один цикл будет делать
foreach ($vals as $v) {
$class = isset($unique[$v->val]) ? 'dupe' : '';
echo '<input type = "text" value = "'.$v->val.'" class = "'. $class .'">' . "\n";
$unique[$v->val] = true;
}
Это хороший момент (я немного торопился ... лол ... уходил с работы примерно через 10 минут)
@ArtisticPhoenix ну, я не уверен, что это то, что нужно. Но я думаю, что для людей, которые найдут эти вопросы и ответы позже, все может пойти по другому пути.
Откуда берутся данные, возможно, лучше исправить дублирование до того, как оно произойдет. ЕСЛИ это невозможно, вы можете использовать комбинацию
array_column
иarray_count_values
(или array_column, и array_unique, array_diff), но мне нужно, чтобы указанный массив был более полезным.