Входные данные
Есть массив предложений:
$sentences = [
"PHP is a popular general-purpose scripting language.",
"Learning PHP can be fun and challenging.",
"Arrays in PHP are very powerful.",
"PHP supports object-oriented programming.",
];
Задания
1️⃣ Посчитать, сколько слов в каждом предложении
Результат:
[
"PHP is a popular general-purpose scripting language." => 8,
"Learning PHP can be fun and challenging." => 7,
...
]
2️⃣ Составить список всех уникальных слов (без повторов, игнорируя регистр, точки и запятые).
3️⃣ Найти слово, которое встречается чаще всего.
Первое решение (черновое)
<?php
$sentences = [
"PHP is a popular general-purpose scripting language.",
"Learning PHP can be fun and challenging.",
"Arrays in PHP are very powerful.",
"PHP supports object-oriented programming.",
];
$countedSentenced = [];
$uniqueWords = [];
$allWords = [];
foreach($sentences as $sentence) {
$words = explode(' ', $sentence);
$countedSentenced[$sentence] = count($words);
// Составить список всех уникальных слов
foreach($words as $word) {
if (!in_array($word, $uniqueWords)) {
$uniqueWords[] = $word;
}
// Найти слово, которое встречается чаще всего
$allWords[] = $word;
}
}
$wordsRating = array_count_values($allWords);
arsort($wordsRating);
$topWord = array_key_first($wordsRating);
print_r($topWord); // PHP
Важные замечания:
- array_count_values() – подсчитывает количество вхождений каждого отдельного значения в массиве. Вот это мы получаем с массива всех слов.
Array
(
[PHP] => 4
[is] => 1
[a] => 1
[popular] => 1
[general-purpose] => 1
[scripting] => 1
[language.] => 1
[Learning] => 1
[can] => 1
[be] => 1
[fun] => 1
[and] => 1
[challenging.] => 1
[Arrays] => 1
[in] => 1
[are] => 1
[very] => 1
[powerful.] => 1
[supports] => 1
[object-oriented] => 1
[programming.] => 1
)
- arsort() – Сортирует массив в порядке убывания, сохраняя ассоциацию индексов. Пример:
<?php
$scores = array("Alice" => 85, "Bob" => 92, "Charlie" => 78, "David" => 92);
arsort($scores); // Сортируем по баллам в порядке убывания
print_r($scores);
// Output
Array
(
[Bob] => 92
[David] => 92
[Alice] => 85
[Charlie] => 78
)
Рефакторинг кода.
Что стоит улучшить (ключевые моменты)
1️⃣ Очистка слов (ОЧЕНЬ ВАЖНО)
Сейчас ты работаешь с «сырыми» словами, надо очищать их от лишних символов:
Array
(
[0] => PHP
[1] => is
[2] => a
[3] => popular
[4] => general-purpose
[5] => scripting
[6] => language.
)
Что делать:
- приводить к нижнему регистру
- убирать знаки препинания
Преподавательский совет:
Любая работа с текстом почти всегда начинается с нормализации данных.
foreach($words as $word) {
/*Очищаем слова*/
$word = strtolower($word);
$word = trim($word, ".,-");
}
Теперь у нас чистые слова.
Array
(
[0] => php
[1] => is
[2] => a
[3] => popular
[4] => general-purpose
[5] => scripting
[6] => language
)
2️⃣ in_array внутри цикла — неэффективно
$uniqueWords = [];
$allWords = [];
foreach($sentences as $sentence) {
$words = explode(' ', $sentence);
$countedSentenced[$sentence] = count($words);
// Составить список всех уникальных слов
foreach($words as $word) {
$word = strtolower($word);
$word = trim($word, ".,-");
if (!in_array($word, $uniqueWords)) {
$uniqueWords[] = $word;
}
}
}
📌 Почему это плохо:
in_array— O(n)- внутри
foreach→ при больших данных будет медленно
💡 Как мыслит опытный PHP-разработчик:
«Если мне нужна уникальность — ключи массива лучше значений»
Как работает in_array
PHP делает следующее:
- Берёт первый элемент массива
$uniqueWords - Сравнивает с
$word - Если не совпало — берёт второй
- Потом третий, четвёртый…
- Пока не найдёт совпадение или не дойдёт до конца массива
👉 Это линейный поиск.
Почему это неэффективно
📈 Временная сложность (упрощённо)
in_array= O(n)foreach ($words as $word)= O(n)
В итоге получается:
O(n) * O(n) = O(n²)
Пример на цифрах
Допустим:
- в тексте 10 000 слов
- уникальных слов — 5 000
Для каждого нового слова PHP в среднем:
- проверяет ~2 500 элементов массива
Итого:
10 000 × 2 500 = 25 000 000 сравнений
А это уже заметно медленно.
Как сделать эффективно?
Использовать массив как set (множество)
В PHP ключи массива хранятся в хеш-таблице.
Проверка существования ключа:
isset($array[$key])
⏱ O(1) — почти мгновенно.
Сравнение подходов
❌ Твой вариант
if (!in_array($word, $uniqueWords)) {
$uniqueWords[] = $word;
}
- поиск по значениям
- каждый раз полный обход
- O(n²)
✅ Правильное мышление
$uniqueWords = [];
foreach ($words as $word) {
$uniqueWords[$word] = true;
}
- слово — ключ
- значение не важно
- повтор перезаписывает, не добавляет
А потом, если нужен список:
$uniqueWordList = array_keys($uniqueWords);
Когда in_array всё-таки ОК
Можно использовать, если:
- массив маленький (10–20 элементов)
- код не в цикле
- важнее читаемость, чем производительность
❗ Но в задачах анализа данных — почти всегда плохая идея
В итоге получаем такой массив уникальных слов.
foreach($words as $word) {
$word = strtolower($word);
$word = trim($word, ".,-");
$uniqueWords[$word] = true;
}
// Output
Array
(
[php] => 1
[is] => 1
[a] => 1
[popular] => 1
[general-purpose] => 1
[scripting] => 1
[language] => 1
[learning] => 1
[can] => 1
[be] => 1
[fun] => 1
[and] => 1
[challenging] => 1
[arrays] => 1
[in] => 1
[are] => 1
[very] => 1
[powerful] => 1
[supports] => 1
[object-oriented] => 1
[programming] => 1
)
Можем теперь получить только ключи.
$uniqueWords = array_keys($uniqueWords);
// Output
Array
(
[0] => php
[1] => is
[2] => a
[3] => popular
[4] => general-purpose
[5] => scripting
[6] => language
[7] => learning
[8] => can
[9] => be
[10] => fun
[11] => and
[12] => challenging
[13] => arrays
[14] => in
[15] => are
[16] => very
[17] => powerful
[18] => supports
[19] => object-oriented
[20] => programming
)
3️⃣ Архитектурное мышление
Сейчас у тебя всё в одном цикле — нормально для начала.
Следующий шаг роста:
- выносить логику в функции
<?php
$sentences = [
"PHP is a popular general-purpose scripting language.",
"Learning PHP can be fun and challenging.",
"Arrays in PHP are very powerful.",
"PHP supports object-oriented programming.",
];
$countedSentenced = [];
$uniqueWords = [];
$allWords = [];
foreach($sentences as $sentence) {
$words = explode(' ', $sentence);
$countedSentenced[$sentence] = count($words);
foreach($words as $word) {
$word = clearString($word);
getUniqueWords($word, $uniqueWords);
getAllWords($word, $allWords);
}
}
$uniqueWords = array_keys($uniqueWords);
$topWord = getPopularWord($allWords);
function clearString($string) {
$string = strtolower($string);
$string = trim($string, ".,-");
return $string;
}
function getUniqueWords($word, &$uniqueWords) {
$uniqueWords[$word] = true;
}
function getAllWords($word, &$allWords) {
$allWords[] = $word;
}
function getPopularWord($allWords) {
$wordsRating = array_count_values($allWords);
arsort($wordsRating);
return array_key_first($wordsRating);
}
print_r($topWord);
Важные замечания:
- Я сначала тут хотел использовать use.
// Before
$uniqueWords = [];
function getUniqueWords($word) use($uniqueWords) {
$uniqueWords[$word] = true;
}
// Error
Parse error: syntax error, unexpected token "use", expecting "{"
Ключевой момент ❗
use нельзя использовать с обычной функцией.
use работает только с анонимными функциями (closures).
$fn = function ($word) use ($uniqueWords) {
$uniqueWords[$word] = true;
};
- передавать внешнее значение в функцию надо по ссылке чтобы изменять его.
// Before
$uniqueWords = [];
function getUniqueWords($word, $uniqueWords) {
$uniqueWords[$word] = true;
}
➡️ передаёт переменную по значению,
а не изменяет оригинальный $uniqueWords.
То есть:
- внутри функции массив меняется
- снаружи — нет
Надо передать массив по ссылке.
$uniqueWords = [];
function getUniqueWords($word, &$uniqueWords) {
$uniqueWords[$word] = true;
}
Почему это правильно
&$uniqueWords— передача по ссылке- функция реально изменяет массив
- это классический PHP-подход
Можно сделать еще лучше: никаких &, только return
Сейчас функция меняет внешний массив».
getUniqueWords($word, $uniqueWords);
getAllWords($word, $allWords);
Надо чтобы функция получала данные → возвращала новые данные».
Это:
- ближе к современному стилю
- безопаснее
- легче тестировать
- легче читать
<?php
$sentences = [
"PHP is a popular general-purpose scripting language.",
"Learning PHP can be fun and challenging.",
"Arrays in PHP are very powerful.",
"PHP supports object-oriented programming.",
];
$countedSentenced = [];
$uniqueWords = [];
$allWords = [];
foreach ($sentences as $sentence) {
$words = explode(' ', $sentence);
$countedSentenced[$sentence] = count($words);
foreach ($words as $word) {
$word = clearString($word);
$uniqueWords = addUniqueWord($word, $uniqueWords);
$allWords = addWord($word, $allWords);
}
}
$uniqueWords = array_keys($uniqueWords);
$topWord = getPopularWord($allWords);
function clearString(string $string): string {
$string = strtolower($string);
$string = trim($string, ".,-");
return $string;
}
function addUniqueWord(string $word, array $uniqueWords): array {
$uniqueWords[$word] = true;
return $uniqueWords;
}
function addWord(string $word, array $allWords): array {
$allWords[] = $word;
return $allWords;
}
function getPopularWord(array $allWords): ?string {
if (empty($allWords)) {
return null;
}
$wordsRating = array_count_values($allWords);
arsort($wordsRating);
return array_key_first($wordsRating);
}
print_r($topWord);
Что здесь принципиально изменилось
1️⃣ Нет побочных эффектов
Функции:
- не знают о внешнем коде
- не меняют ничего «сами по себе»
- Функции возвращают обновлённый массив.
Это чистые функции
2️⃣ Код легче тестировать
3️⃣ Это стиль фреймворков
Коротко — как это запомнить
| Подход | Когда использовать |
|---|---|
& | низкоуровневый код, оптимизация |
return | 90% бизнес-логики |
global | ❌ никогда |