Step 1 of 5 · Reading · ~3 min
Learn
Arrays
Counting Distinct Values
"How many different words are in this line?" sounds trivial until you notice PHP has no Set type. It does not need one: an array's keys are already a hash table, and there are three builtins covering the common jobs.
| Goal | Tool |
|---|---|
| Drop duplicate values | array_unique($arr) |
| Ask "have I seen this?" quickly | the keys — assign, then isset() |
| Count how often each value appears | array_count_values($arr) |
array_unique
<?php
$words = ["the", "quick", "brown", "the", "fox"];
print_r(array_unique($words));
echo count(array_unique($words)), "\n";
//> Array
//> (
//> [0] => the
//> [1] => quick
//> [2] => brown
//> [4] => fox
//> )
//> 4
Two details are doing real work there.
It keeps the original keys. The second "the" lived at index 3, so index 3 is simply gone and the result is sparse. count() does not care, but $unique[3] no longer exists. Wrap it in array_values() if you need a clean list.
It compares values as strings by default. Values are converted to text before comparison, so numbers and their string spellings collapse together:
<?php
print_r(array_unique([1, "1", 1.0, true]));
//> Array
//> (
//> [0] => 1
//> )
Pass SORT_REGULAR as the second argument to compare with == rather than by string conversion.
Keys as a set
The other approach builds the set yourself. Every value becomes a key; whatever you store alongside it is irrelevant.
<?php
$words = ["the", "quick", "brown", "the", "fox"];
$seen = [];
foreach ($words as $w) {
$seen[$w] = true;
}
echo count($seen), "\n";
var_dump(isset($seen["fox"]));
var_dump(isset($seen["cat"]));
//> 4
//> bool(true)
//> bool(false)
Assigning the same key twice just overwrites it, so duplicates cost nothing at all.
| ✗ Linear scan | ✓ Keys as a set |
|---|---|
if (!in_array($w, $out)) $out[] = $w; | $seen[$w] = true; |
| Rechecks the whole list every time | One hash lookup |
| overall | overall |
in_array inside a loop is the classic beginner shape, and it is quietly quadratic. For a handful of words nobody notices; for a log file it is the difference between instant and lunch.
array_flip($arr) builds the same structure in one call — it swaps keys and values, so the values become the keys.
Frequencies in one call
<?php
$words = ["the", "quick", "brown", "the", "fox"];
$counts = array_count_values($words);
print_r($counts);
arsort($counts);
echo array_key_first($counts), "\n";
//> Array
//> (
//> [the] => 2
//> [quick] => 1
//> [brown] => 1
//> [fox] => 1
//> )
//> the
arsort() sorts by value, descending, keeping every key attached to its own count — exactly what a "top word" report needs. Note that array_count_values only accepts int and string values; anything else is skipped with a warning.
Your exercise
Distinct Words reads one line of space-separated words and prints how many different words it contains.
The starter splits the line into $words with explode. The mistake the grader catches is counting the wrong array: the first test feeds the quick brown the, so count($words) is 4 while the expected answer is 3. Remove the duplicates before you count — count(array_unique($words)) — or build the keys-as-a-set version and count that; both are correct. The second test feeds a a a and expects 1, which rules out the shortcut of subtracting one per repeat: count($words) - 1 happens to pass the first test and fails this one. Print just the number, then a newline.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…