2727. Is Object Empty
Problem Description
The problem asks you to determine whether a given object or array is empty.
An empty object is defined as an object that contains no key-value pairs. For example, {}
is empty, while {a: 1}
is not empty.
An empty array is defined as an array that contains no elements. For example, []
is empty, while [1]
is not empty.
The input will be either a JavaScript object or an array that is guaranteed to be valid output from JSON.parse
. This means you don't need to handle invalid JSON or other data types.
Your task is to implement a function isEmpty
that:
- Takes one parameter: either an object or an array
- Returns
true
if the input is empty (no properties for objects, no elements for arrays) - Returns
false
if the input contains at least one property or element
The solution uses a for...in
loop to iterate through the properties of the object or elements of the array. If the loop enters even once, it means there's at least one property/element, so the function immediately returns false
. If the loop never executes (because there are no properties/elements), the function returns true
.
Intuition
The key insight is that both objects and arrays in JavaScript can be iterated using the for...in
loop. This loop will iterate over all enumerable properties of an object or all indices of an array.
If an object or array is empty, the for...in
loop will never execute its body because there are no properties or indices to iterate over. On the other hand, if there's even a single property or element, the loop will execute at least once.
This leads to a clever approach: instead of checking the length or counting properties, we can simply try to enter the loop. If we can enter the loop even once, we know the object/array is not empty, so we immediately return false
. If we never enter the loop, we know it's empty and return true
after the loop.
This approach works uniformly for both objects and arrays without needing to distinguish between them. For objects, for...in
iterates over keys like "name"
, "age"
, etc. For arrays, it iterates over indices like "0"
, "1"
, "2"
, etc. In both cases, an empty structure means the loop body never executes.
The elegance of this solution lies in its simplicity - we don't need to use Object.keys()
, check length
properties, or write separate logic for objects versus arrays. The for...in
loop handles both cases with the same logic, making the code concise and efficient.
Solution Approach
The implementation uses a single for...in
loop to check if the object or array is empty:
function isEmpty(obj: Record<string, any> | any[]): boolean {
for (const x in obj) {
return false;
}
return true;
}
Let's walk through how this works step by step:
-
The
for...in
loop: This loop iterates over all enumerable properties of an object or all indices of an array. The variablex
will hold the property name or array index during each iteration. -
Early return pattern: Inside the loop body, we immediately return
false
. This means if the loop executes even once (indicating at least one property or element exists), the function returnsfalse
right away. -
Default return: If the loop never executes (because there are no properties or elements to iterate over), the code continues past the loop and returns
true
.
Example walkthrough with an empty object {}
:
- The
for...in
loop attempts to iterate over the object - Since there are no properties, the loop body never executes
- The function continues to the
return true
statement - Result:
true
(the object is empty)
Example walkthrough with a non-empty array [1, 2]
:
- The
for...in
loop starts iterating - On the first iteration,
x
would be"0"
(the first index) - The loop body executes and immediately returns
false
- Result:
false
(the array is not empty)
This solution has O(1) time complexity in the best case (non-empty input) since it returns immediately upon finding the first property/element. In the worst case (empty input), it's still O(1) as there's nothing to iterate. The space complexity is O(1) as we only use a single loop variable.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with two concrete examples to see how the for...in
loop approach works:
Example 1: Non-empty object {name: "Alice", age: 25}
function isEmpty(obj) {
for (const x in obj) {
return false; // <-- We'll hit this line
}
return true;
}
isEmpty({name: "Alice", age: 25})
Step-by-step execution:
- The
for...in
loop starts and finds the first property"name"
- The loop variable
x
is set to"name"
- The loop body executes immediately
- We return
false
right away - no need to check"age"
or any other properties - Result:
false
(object is not empty)
Example 2: Empty array []
function isEmpty(obj) {
for (const x in obj) {
return false; // <-- We never reach this line
}
return true; // <-- We end up here
}
isEmpty([])
Step-by-step execution:
- The
for...in
loop attempts to iterate over array indices - Since the array has no elements, there are no indices (no "0", "1", etc.)
- The loop condition fails immediately - the loop body never executes
- Execution continues past the loop to the next statement
- We return
true
- Result:
true
(array is empty)
The beauty of this approach is that we don't need to check if the input is an object or array, count properties, or use different methods - the for...in
loop handles both cases identically. As soon as we find any property or element, we know it's not empty and return immediately.
Solution Implementation
1def isEmpty(obj):
2 """
3 Checks if an object (dict) or list is empty (has no elements/keys)
4
5 Args:
6 obj: The dict or list to check for emptiness
7
8 Returns:
9 bool: True if the dict/list is empty, False otherwise
10 """
11 # Iterate through all elements/keys in the object
12 for key in obj:
13 # If any element/key exists, the object is not empty
14 return False
15 # No elements/keys found, the object is empty
16 return True
17
1/**
2 * Checks if an object (Map) or array is empty (has no elements)
3 * @param obj - The Map or array to check for emptiness
4 * @return true if the Map/array is empty, false otherwise
5 */
6public static boolean isEmpty(Object obj) {
7 // Check if the input is a Map
8 if (obj instanceof Map) {
9 Map<?, ?> map = (Map<?, ?>) obj;
10 // If the map has any entries, it's not empty
11 return map.isEmpty();
12 }
13 // Check if the input is an array
14 else if (obj != null && obj.getClass().isArray()) {
15 // Get the length of the array using reflection
16 int length = java.lang.reflect.Array.getLength(obj);
17 // Return true if array length is 0, false otherwise
18 return length == 0;
19 }
20 // Check if the input is a Collection (List, Set, etc.)
21 else if (obj instanceof Collection) {
22 Collection<?> collection = (Collection<?>) obj;
23 // Return true if collection has no elements
24 return collection.isEmpty();
25 }
26 // For null or unsupported types, consider as empty
27 return true;
28}
29
1#include <unordered_map>
2#include <vector>
3#include <any>
4
5/**
6 * Checks if a container (map or vector) is empty
7 * @param container - The container to check for emptiness
8 * @returns true if the container is empty, false otherwise
9 */
10template<typename T>
11bool isEmpty(const T& container) {
12 // Check if the container has no elements
13 return container.empty();
14}
15
16// Overload for unordered_map (similar to JavaScript object)
17bool isEmpty(const std::unordered_map<std::string, std::any>& obj) {
18 // Check if the map has no key-value pairs
19 return obj.empty();
20}
21
22// Overload for vector (similar to JavaScript array)
23template<typename T>
24bool isEmpty(const std::vector<T>& arr) {
25 // Check if the vector has no elements
26 return arr.empty();
27}
28
29// Alternative implementation that mimics the original JavaScript logic more closely
30template<typename T>
31bool isEmptyIterative(const T& container) {
32 // Iterate through the container
33 for (auto it = container.begin(); it != container.end(); ++it) {
34 // If any element exists, the container is not empty
35 return false;
36 }
37 // No elements found, the container is empty
38 return true;
39}
40
1/**
2 * Checks if an object or array is empty (has no enumerable properties)
3 * @param obj - The object or array to check for emptiness
4 * @returns true if the object/array is empty, false otherwise
5 */
6function isEmpty(obj: Record<string, any> | any[]): boolean {
7 // Iterate through all enumerable properties of the object/array
8 for (const key in obj) {
9 // If any property exists, the object/array is not empty
10 return false;
11 }
12 // No properties found, the object/array is empty
13 return true;
14}
15
Time and Space Complexity
Time Complexity: O(1)
The function uses a for...in
loop to iterate over the properties of the object or array. However, the loop returns immediately upon encountering the first property/element. In the worst case (empty object/array), the loop doesn't iterate at all and returns true
. In the best case (non-empty object/array), it returns false
on the first iteration. Therefore, the function performs at most one iteration, making the time complexity constant O(1)
.
Space Complexity: O(1)
The function only uses a single loop variable x
to store the current property key during iteration. No additional data structures are created that scale with the input size. The space usage remains constant regardless of the size of the input object or array, resulting in O(1)
space complexity.
Common Pitfalls
Pitfall 1: Confusing for...in
behavior with inherited properties
In JavaScript, for...in
loops iterate over all enumerable properties in the prototype chain, not just the object's own properties. While this isn't an issue for arrays or objects created from JSON.parse()
(which only have own properties), it can cause unexpected behavior in other contexts.
Example of the pitfall:
const obj = Object.create({ inherited: true });
// obj has no own properties, but has an inherited property
console.log(isEmpty(obj)); // Returns false (unexpected!)
// The for...in loop sees the inherited property
Solution:
Use hasOwnProperty()
check or Object.keys()
:
function isEmpty(obj) {
for (const x in obj) {
if (obj.hasOwnProperty(x)) {
return false;
}
}
return true;
}
// Alternative approach using Object.keys()
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
Pitfall 2: Performance considerations for sparse arrays
When dealing with sparse arrays (arrays with gaps in indices), for...in
only iterates over defined indices, which might be counterintuitive compared to checking the length
property.
Example of the pitfall:
const sparseArray = new Array(1000);
sparseArray[999] = 'value';
// This array has length 1000 but only one actual element
// Using for...in (current solution) - iterates only once
isEmpty(sparseArray); // Returns false quickly
// If someone mistakenly uses array.length
function isEmptyWrong(arr) {
return arr.length === 0; // Would return false for empty sparse arrays
}
Solution:
The current for...in
approach actually handles this correctly, but developers should be aware that it checks for actual elements, not the array's length property.
Pitfall 3: Python-specific consideration with different iterable types
In Python, the iteration behavior differs slightly between dictionaries and lists. When iterating over a dictionary, you iterate over keys, while for lists you iterate over values.
Example of the pitfall:
# This works correctly but might be confusing
d = {"key": "value"}
for item in d: # item is "key", not "value"
print(item) # Prints: "key"
l = ["value"]
for item in l: # item is "value"
print(item) # Prints: "value"
Solution: The current implementation works correctly because we only care about the existence of items, not their values. However, for clarity, you might want to be explicit:
def isEmpty(obj):
# More explicit approach
if isinstance(obj, dict):
return len(obj.keys()) == 0
elif isinstance(obj, list):
return len(obj) == 0
# Or simply use len() for both
return len(obj) == 0
Which algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!