PHP
Arrays
Programming
Data Structures
Coding Tips

PHP Arrays - Separate Identical Values

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Separating identical values in a PHP array can mean several different things: counting duplicates, grouping equal values, or splitting the input into unique and repeated items. The right approach depends on the desired output shape, because the best function for counts is not always the best function for preserving order or retaining full row context.

Count Repeated Scalar Values First

If the array contains scalar values and you want to know how often each value appears, array_count_values is the simplest and usually the fastest tool.

php
1<?php
2$items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
3$counts = array_count_values($items);
4
5print_r($counts);

That produces a frequency map where repeated values are immediately visible.

From there, duplicates and uniques are easy to derive.

php
1<?php
2$duplicates = array_filter($counts, fn($count) => $count > 1);
3$uniques = array_keys(array_filter($counts, fn($count) => $count === 1));
4
5print_r($duplicates);
6print_r($uniques);

This is the right answer when you care about counts more than about the exact original row positions.

Preserve Original Order When Splitting

If the result should preserve the order of the original input, do the count first and then walk the original array again.

php
1<?php
2$items = ['x', 'y', 'x', 'z', 'y', 'q'];
3$counts = array_count_values($items);
4
5$uniqueInOrder = [];
6$duplicateInOrder = [];
7
8foreach ($items as $item) {
9    if ($counts[$item] === 1) {
10        $uniqueInOrder[] = $item;
11    } else {
12        $duplicateInOrder[] = $item;
13    }
14}
15
16print_r($uniqueInOrder);
17print_r($duplicateInOrder);

That gives you a clean split while keeping the original sequence intact.

Group Full Records by a Duplicate Key

When the data is an array of associative arrays, you usually do not want only the repeated scalar values. You want to keep the full rows grouped by the repeated field.

php
1<?php
2$rows = [
3    ['id' => 1, 'email' => '[email protected]'],
4    ['id' => 2, 'email' => '[email protected]'],
5    ['id' => 3, 'email' => '[email protected]'],
6    ['id' => 4, 'email' => '[email protected]'],
7];
8
9$groups = [];
10foreach ($rows as $row) {
11    $key = $row['email'];
12    $groups[$key][] = $row;
13}
14
15$duplicateGroups = array_filter($groups, fn($bucket) => count($bucket) > 1);
16print_r($duplicateGroups);

This is more useful than a plain frequency map when you need the full duplicate records for review, reporting, or cleanup.

Normalize Before Separating Values

Human-equivalent values are not always byte-identical. Case differences and surrounding whitespace can turn obvious duplicates into different buckets unless you normalize first.

php
1<?php
2$items = [' Apple', 'apple', 'APPLE ', 'Banana'];
3$normalized = [];
4
5foreach ($items as $raw) {
6    $normalized[] = mb_strtolower(trim($raw));
7}
8
9print_r(array_count_values($normalized));

Whether this is correct depends on the business rule. Sometimes case should matter. Sometimes it should not. The important thing is to decide explicitly.

Avoid Quadratic Duplicate Checks

A common beginner approach is nested loops that compare every value to every other value. That works on tiny arrays and scales badly.

Using a frequency map or grouping map is usually O(n) with respect to the number of elements, while repeated scans quickly become expensive. If the array can grow large, build the right structure once and reuse it.

Build a Reusable Helper

If the same duplicate logic appears in several places, wrap it in one helper so the policy is centralized.

php
1<?php
2function splitByDuplicateValues(array $values): array
3{
4    $counts = array_count_values($values);
5    $unique = [];
6    $duplicate = [];
7
8    foreach ($values as $value) {
9        if ($counts[$value] === 1) {
10            $unique[] = $value;
11        } else {
12            $duplicate[] = $value;
13        }
14    }
15
16    return [
17        'unique' => $unique,
18        'duplicate' => $duplicate,
19        'counts' => $counts,
20    ];
21}
22
23print_r(splitByDuplicateValues(['a', 'b', 'a', 'c']));

A helper makes the behavior easier to test and easier to change later if the normalization or output shape changes.

Common Pitfalls

The most common mistake is using array_unique when the real need is to know which values repeat and how often. Another is forgetting that duplicates among records usually need row grouping, not just scalar counts.

Developers also often skip normalization, then wonder why values that look identical to users are treated as different buckets.

Finally, avoid nested loops for large arrays unless the data size is truly trivial and the code path is not performance-sensitive.

Summary

  • Decide first whether you need counts, grouped rows, or a unique-versus-duplicate split.
  • Use array_count_values for scalar frequency analysis.
  • Use a second pass if you need to preserve original order.
  • Group associative rows by the duplicate field when full context matters.
  • Normalize values explicitly when case and whitespace should not affect grouping.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.