#php #arrays #multidimensional-array #unique
#php #массивы #многомерный массив #уникальное
Вопрос:
У меня есть многомерный массив под названием users, который отформатирован следующим образом, и я пытаюсь создать скрипт, который создаст «имя пользователя» на основе этой информации:
$users = [
['first_name' => 'Bob', 'last_name' => 'Smith'],
['first_name' => 'Steve', 'last_name' => 'Little'],
['first_name' => 'Eric', 'last_name' => 'Fielder'],
['first_name' => 'Steve', 'last_name' => 'Richardson'],
['first_name' => 'Bob', 'last_name' => 'Sanders'],
['first_name' => 'Bob', 'last_name' => 'Sanders'],
['first_name' => 'Bob', 'last_name' => 'Smith'],
];
Требуемая логика:
-
Если нет повторяющихся имен, в качестве имени пользователя используется только первое имя («Eric«).
-
Если есть два имени с одинаковым именем, но разными начальными буквами в фамилии, то в качестве последней инициализации будет использоваться имя («Стив Л.» и «Стив Р.«).
-
Если у нескольких человек есть последнее имя и инициал, то оно возвращает полное имя («Боб Смит» и «Боб Сандерс«).
-
Наконец, если найдено одно и то же точное имя, то к каждому из них будет добавлено число, подобное этому: «Боб Сандерс (1)» и «Боб Сандерс (2)«
Я надеюсь, что это можно сделать эффективно и без большого количества циклов, но я не могу понять это, хоть убей.
Ответ №1:
Этот скрипт не такой изящный, но в значительной степени делает то, что вы хотите. Обратите внимание, что он использует только два цикла, но требует дополнительной памяти для хранения метаданных о пользователях:
<?php
$users = array(
array("first_name"=>"Bob", "last_name"=>"Smith"),
array("first_name"=>"Steve", "last_name"=>"Little"),
array("first_name"=>"Eric", "last_name"=>"Fielder"),
array("first_name"=>"Steve", "last_name"=>"Richardson"),
array("first_name"=>"Bob", "last_name"=>"Sanders"),
array("first_name"=>"Bob", "last_name"=>"Sanders")
);
$_users_info = array("first_name_count"=>array(),"last_name_count"=>array(),"first_name_last_initial_count"=>array());
foreach($users as $user){
$_users_info["first_name_count"][$user["first_name"]] = isset($_users_info["first_name_count"][$user["first_name"]]) ? $_users_info["first_name_count"][$user["first_name"]] : 1;
$_users_info["last_name_count"][$user["last_name"]] = isset($_users_info["last_name_count"][$user["last_name"]]) ? $_users_info["last_name_count"][$user["last_name"]] : 1;
$_users_info["first_name_last_initial_count"][$user["first_name"]."#".substr($user["last_name"],0,1)] = isset($_users_info["first_name_last_initial_count"][$user["first_name"]."#".substr($user["last_name"],0,1)]) ? $_users_info["first_name_last_initial_count"][$user["first_name"]."#".substr($user["last_name"],0,1)] : 1;
$_users_info["complete_name_count"][$user["first_name"]."#".$user["last_name"]] = isset($_users_info["complete_name_count"][$user["first_name"]."#".$user["last_name"]]) ? $_users_info["complete_name_count"][$user["first_name"]."#".$user["last_name"]] : 1;
$_users_info["complete_name_allocated"][$user["first_name"]."#".$user["last_name"]] = 0;
}
print('<pre>');
foreach($users as $user) {
$username = null;
if($_users_info["first_name_count"][$user["first_name"]]==1) $username = $user["first_name"];
else if($_users_info["first_name_last_initial_count"][$user["first_name"]."#".substr($user["last_name"],0,1)]==1) $username = $user["first_name"]." ".substr($user["last_name"],0,1).".";
else if($_users_info["last_name_count"][$user["last_name"]]==1) $username = $user["first_name"]." ".$user["last_name"];
else $username = $user["first_name"]." ".$user["last_name"].sprintf(" (%d)", $_users_info["complete_name_allocated"][$user["first_name"]."#".$user["last_name"]]);
printf("%s %s => %sn",$user["first_name"],$user["last_name"],$username);
}
print('</pre>');
?>
Комментарии:
1. Просто убедитесь, что имена были очищены заранее: стандартизируйте регистр и удалите лишние пробелы / символы.
Ответ №2:
Я нахожу фрагмент Nayru чрезмерно широким, сложным для отслеживания и слишком дорогим с точки зрения памяти — он хранит избыточные подсчеты ради удобства поиска. К его чести, он поддерживает порядок строк — если это имеет значение.
Другой метод заключается в объединении входных данных во вложенные группы (с уникальными уровнями / ключами), затем повторять эти объединенные уровни и использовать набор условий для генерации желаемых имен пользователей. Это может быть наиболее компактным способом отслеживания коллизий имен. Я, конечно, чувствую, что это гораздо более простой фрагмент кода для поддержки и чтения.
* если ваши фамилии могут начинаться с многобайтового символа, то mb_substr()
следует использовать для выделения первой буквы
* результат этого фрагмента не соответствует первоначальному порядку ввода, но при необходимости его можно переработать для этой цели.
* в нем используется несколько циклов, но это всего лишь наиболее эффективное средство для повторения вложенных уровней — от него не следует уклоняться.
Код: (демо)
foreach ($users as $row) {
$grouped[$row['first_name']][$row['last_name'][0] ?? ''][$row['last_name']][] = $row;
}
$result = [];
foreach ($grouped as $firstName => $leadingLetterGroup) {
$leadingLetterCount = count($leadingLetterGroup);
foreach ($leadingLetterGroup as $leadingLetter => $lastNameGroup) {
$lastNameCount = count($lastNameGroup);
foreach ($lastNameGroup as $lastName => $rows) {
if (count($rows) === 1) {
if ($leadingLetterCount === 1) {
$username = $firstName;
} elseif ($lastNameCount === 1) {
$username = "$firstName $leadingLetter.";
} else {
$username = "$firstName $lastName";
}
$result[] = $rows[0] ['username' => $username];
} else {
foreach ($rows as $i => $row) {
$username = sprintf("%s %s (%d)", $firstName, $lastName, $i 1);
$result[] = $row ['username' => $username];
}
}
}
}
}
var_export($result);
Вывод:
array (
0 =>
array (
'first_name' => 'Bob',
'last_name' => 'Smith',
'username' => 'Bob Smith (1)',
),
1 =>
array (
'first_name' => 'Bob',
'last_name' => 'Smith',
'username' => 'Bob Smith (2)',
),
2 =>
array (
'first_name' => 'Bob',
'last_name' => 'Sanders',
'username' => 'Bob Sanders (1)',
),
3 =>
array (
'first_name' => 'Bob',
'last_name' => 'Sanders',
'username' => 'Bob Sanders (2)',
),
4 =>
array (
'first_name' => 'Steve',
'last_name' => 'Little',
'username' => 'Steve L.',
),
5 =>
array (
'first_name' => 'Steve',
'last_name' => 'Richardson',
'username' => 'Steve R.',
),
6 =>
array (
'first_name' => 'Eric',
'last_name' => 'Fielder',
'username' => 'Eric',
),
)