How to remove the duplicate items in the list without using any built in methods like (contains, toSet(), where, indexOf) in flutter with some proper examples
Answer
Overview
This is a classic DSA interview question that tests your ability to solve problems from scratch without relying on Dart's built-in convenience methods. You must manually track which items you've already seen and build a new list with only unique items.
Method 1: Nested For Loop (Brute Force)
Compare each element with every element in the result list manually.
dartList<int> removeDuplicates(List<int> input) { List<int> result = []; for (int i = 0; i < input.length; i++) { bool isDuplicate = false; // Check if input[i] already exists in result for (int j = 0; j < result.length; j++) { if (input[i] == result[j]) { isDuplicate = true; break; // No need to check further } } // Only add if not found in result if (!isDuplicate) { result.add(input[i]); } } return result; } void main() { List<int> numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]; print(removeDuplicates(numbers)); // [3, 1, 4, 5, 9, 2, 6] }
Time Complexity: O(n²) — for each element, scan the result list Space Complexity: O(n) — result list
Method 2: Using a Map to Track Seen Items
Use a
MapdartList<int> removeDuplicatesWithMap(List<int> input) { List<int> result = []; Map<int, bool> seen = {}; // Track which items we've seen for (int i = 0; i < input.length; i++) { if (seen[input[i]] == null) { // Not seen before (no contains!) seen[input[i]] = true; // Mark as seen result.add(input[i]); // Add to result } } return result; } void main() { List<int> numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]; print(removeDuplicatesWithMap(numbers)); // [3, 1, 4, 5, 9, 2, 6] }
Time Complexity: O(n) — single pass, Map lookup is O(1) Space Complexity: O(n) — Map + result list
Why this is better: Map key lookup (
) is O(1) average, so the total is O(n) instead of O(n²).textmap[key]
Method 3: Sort First, Then Remove Adjacent Duplicates
Sort the list first so duplicates are next to each other, then just compare each element with the previous one.
dart// Simple bubble sort (no built-in sort) List<int> bubbleSort(List<int> input) { List<int> list = []; for (int i = 0; i < input.length; i++) { list.add(input[i]); // Manual copy } for (int i = 0; i < list.length - 1; i++) { for (int j = 0; j < list.length - i - 1; j++) { if (list[j] > list[j + 1]) { // Swap int temp = list[j]; list[j] = list[j + 1]; list[j + 1] = temp; } } } return list; } List<int> removeDuplicatesSorted(List<int> input) { if (input.length == 0) return []; List<int> sorted = bubbleSort(input); List<int> result = [sorted[0]]; // First element is always unique for (int i = 1; i < sorted.length; i++) { // Only add if different from previous element if (sorted[i] != sorted[i - 1]) { result.add(sorted[i]); } } return result; } void main() { List<int> numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]; print(removeDuplicatesSorted(numbers)); // [1, 2, 3, 4, 5, 6, 9] // ⚠️ Note: order changes because of sorting }
Time Complexity: O(n²) for bubble sort + O(n) for dedup = O(n²) Space Complexity: O(n)
Trade-off: This changes the original order. Use Method 1 or 2 if order must be preserved.
Method 4: In-Place Removal (No Extra List)
Remove duplicates by modifying the original list — no extra result list needed.
dartList<int> removeDuplicatesInPlace(List<int> input) { // Create a working copy List<int> list = []; for (int i = 0; i < input.length; i++) { list.add(input[i]); } int i = 0; while (i < list.length) { int j = i + 1; while (j < list.length) { if (list[i] == list[j]) { // Remove duplicate by shifting elements left for (int k = j; k < list.length - 1; k++) { list[k] = list[k + 1]; } list.removeLast(); // Shrink list // Don't increment j — new element shifted into position j } else { j++; } } i++; } return list; } void main() { List<int> numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]; print(removeDuplicatesInPlace(numbers)); // [3, 1, 4, 5, 9, 2, 6] }
Time Complexity: O(n²) — nested loops with shifting Space Complexity: O(1) extra (modifies in-place)
Method 5: Works with Strings and Custom Objects
String List
dartList<String> removeDuplicateStrings(List<String> input) { List<String> result = []; Map<String, bool> seen = {}; for (int i = 0; i < input.length; i++) { if (seen[input[i]] == null) { seen[input[i]] = true; result.add(input[i]); } } return result; } void main() { List<String> fruits = ['apple', 'banana', 'apple', 'cherry', 'banana', 'date']; print(removeDuplicateStrings(fruits)); // [apple, banana, cherry, date] }
Custom Objects (Compare by specific field)
dartclass User { String id; String name; User(this.id, this.name); String toString() => 'User($id, $name)'; } List<User> removeDuplicateUsers(List<User> input) { List<User> result = []; Map<String, bool> seenIds = {}; for (int i = 0; i < input.length; i++) { if (seenIds[input[i].id] == null) { seenIds[input[i].id] = true; result.add(input[i]); } } return result; } void main() { List<User> users = [ User('1', 'Alice'), User('2', 'Bob'), User('1', 'Alice Duplicate'), // Same ID User('3', 'Charlie'), User('2', 'Bob Duplicate'), // Same ID ]; print(removeDuplicateUsers(users)); // [User(1, Alice), User(2, Bob), User(3, Charlie)] }
Generic Version (Works with Any Type)
dartList<T> removeDups<T>(List<T> input, String Function(T) getKey) { List<T> result = []; Map<String, bool> seen = {}; for (int i = 0; i < input.length; i++) { String key = getKey(input[i]); if (seen[key] == null) { seen[key] = true; result.add(input[i]); } } return result; } void main() { // Works with int var nums = removeDups<int>([1, 2, 1, 3, 2], (n) => n.toString()); print(nums); // [1, 2, 3] // Works with String var strs = removeDups<String>(['a', 'b', 'a'], (s) => s); print(strs); // [a, b] // Works with User var users = removeDups<User>( [User('1', 'Alice'), User('1', 'Dup')], (u) => u.id, ); print(users); // [User(1, Alice)] }
All Methods Comparison
| Method | Time | Space | Preserves Order? | Best For |
|---|---|---|---|---|
| Nested Loop | O(n²) | O(n) | Yes | Small lists, simple approach |
| Map Tracking | O(n) | O(n) | Yes | Best overall performance |
| Sort + Adjacent | O(n²) | O(n) | No | When order doesn't matter |
| In-Place | O(n²) | O(1) | Yes | Memory-constrained |
| Generic | O(n) | O(n) | Yes | Custom objects, reusable |
Interview Tips
If asked this question:
- Start with Method 1 (Nested Loop) — shows you understand the problem
- Then optimize to Method 2 (Map) — shows you can think about time complexity
- Mention Method 3 (Sort) as an alternative — shows breadth of knowledge
- Discuss trade-offs — order preservation vs performance
Key Takeaway: Without built-in methods, use a
as a manual hash set for O(n) performance. The Map key lookup (textMap) replacestextmap[key] == nullwithout using it directly.textcontains()