2675. Array of Objects to Matrix 🔒
Problem Description
You need to convert an array of objects into a matrix (2D array) representation.
The input arr
is an array where each element can be:
- An object (potentially with nested objects/arrays)
- An array (potentially with nested objects/arrays)
- Primitive values (numbers, strings, booleans, null)
The output matrix should be structured as follows:
First Row (Headers):
- Contains column names derived from all unique keys found across all objects in the array
- For nested objects, the column name is the path to that value, with levels separated by dots (
.
) - For example, if an object has
{user: {name: "John"}}
, the column would be"user.name"
- Column names must be sorted in lexicographical (alphabetical) order
Data Rows:
- Each subsequent row represents one object from the input array
- Values are placed in their corresponding columns based on the headers
- If an object doesn't have a value for a particular column, use an empty string (
""
)
Example: If the input is:
[ {a: 1, b: {c: 2}}, {a: 3, b: {c: 4, d: 5}} ]
The output matrix would be:
[ ["a", "b.c", "b.d"], // Headers (sorted) [1, 2, ""], // First object (no b.d) [3, 4, 5] // Second object ]
The challenge involves:
- Recursively traversing nested structures to extract all possible paths
- Collecting all unique column names across all objects
- Mapping each object's values to the correct columns
- Handling missing values appropriately
Intuition
The key insight is that we need to flatten nested objects into a single-level representation where each nested path becomes a unique key. Think of it like converting a tree structure into a flat table format.
To achieve this transformation, we can break down the problem into three main steps:
-
Flatten each object into key-value pairs: For nested structures, we need to recursively traverse and create dot-separated paths. For example,
{a: {b: 1}}
becomes{"a.b": 1}
. This flattening process naturally handles any level of nesting by building up the path as we go deeper. -
Collect all unique column names: Once we have flattened representations of all objects, we can gather all unique keys (paths) that appear across any object. These become our column headers. Sorting them lexicographically ensures consistent column ordering.
-
Build the matrix row by row: For each original object, we create a row by looking up values for each column. If a particular path doesn't exist in that object, we fill it with an empty string.
The recursive depth-first search (DFS) approach works well here because:
- When we encounter a primitive value (number, string, boolean, null), we've reached a leaf node and can return the key-value pair
- When we encounter an object or array, we need to go deeper, appending the current key to the path
- By flattening the results at each level, we ultimately get a flat array of key-value pairs for each object
This approach elegantly handles the variable structure of input objects - some might be deeply nested while others are flat, some might have certain paths while others don't. The flattening strategy normalizes everything into a consistent format that can be easily converted into a matrix.
Solution Approach
The implementation uses a recursive DFS (Depth-First Search) approach to flatten nested objects and then constructs the matrix from the flattened data.
Step 1: Define the DFS function for flattening
The dfs
function takes two parameters:
key
: The current path as a string (dot-separated)obj
: The current object/value being processed
const dfs = (key: string, obj: any) => {
// Base case: primitive values
if (typeof obj === 'number' || typeof obj === 'string' ||
typeof obj === 'boolean' || obj === null) {
return { [key]: obj };
}
// Recursive case: objects/arrays
const res: any[] = [];
for (const [k, v] of Object.entries(obj)) {
const newKey = key ? `${key}.${k}` : `${k}`;
res.push(dfs(newKey, v));
}
return res.flat();
};
For primitive values, we return an object with the accumulated path as the key. For objects/arrays, we iterate through each property, build the new path by appending the current key with a dot separator, and recursively process each value. The flat()
method ensures we get a single-level array of key-value objects.
Step 2: Flatten all objects in the input array
const kv = arr.map(obj => dfs('', obj));
We map over the input array, calling dfs
with an empty initial key for each object. This gives us an array where each element is an array of flattened key-value pairs.
Step 3: Extract and sort unique column names
const keys = [
...new Set(
kv.flat()
.map(obj => Object.keys(obj))
.flat()
)
].sort();
We flatten the array of key-value pairs, extract all keys, use a Set
to get unique values, and sort them lexicographically. These become our column headers.
Step 4: Build the matrix
const ans: any[] = [keys]; // Start with headers
for (const row of kv) {
const newRow: any[] = [];
for (const key of keys) {
const v = row.find(r => r.hasOwnProperty(key))?.[key];
newRow.push(v === undefined ? '' : v);
}
ans.push(newRow);
}
We initialize the result matrix with the headers as the first row. Then for each original object (represented by its flattened key-value pairs), we create a new row by:
- Iterating through each column name in order
- Finding the corresponding value in the flattened representation
- Using an empty string if the value doesn't exist
- Adding the completed row to the matrix
The use of hasOwnProperty
ensures we correctly handle cases where a value might be undefined
(which should be preserved) versus not existing at all (which should become an empty string).
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 a small example to illustrate the solution approach:
Input:
[ {name: "Alice", age: 30}, {name: "Bob", details: {age: 25, city: "NYC"}} ]
Step 1: Flatten each object using DFS
For the first object {name: "Alice", age: 30}
:
- Call
dfs("", {name: "Alice", age: 30})
- Process
name: "Alice"
→dfs("name", "Alice")
returns{name: "Alice"}
- Process
age: 30
→dfs("age", 30)
returns{age: 30}
- Result:
[{name: "Alice"}, {age: 30}]
For the second object {name: "Bob", details: {age: 25, city: "NYC"}}
:
- Call
dfs("", {name: "Bob", details: {...}})
- Process
name: "Bob"
→ returns{name: "Bob"}
- Process
details: {age: 25, city: "NYC"}
:- Call
dfs("details", {age: 25, city: "NYC"})
- Process
age: 25
→dfs("details.age", 25)
returns{details.age: 25}
- Process
city: "NYC"
→dfs("details.city", "NYC")
returns{details.city: "NYC"}
- Call
- Result:
[{name: "Bob"}, {details.age: 25}, {details.city: "NYC"}]
After flattening, we have:
kv = [ [{name: "Alice"}, {age: 30}], [{name: "Bob"}, {details.age: 25}, {details.city: "NYC"}] ]
Step 2: Extract and sort unique column names
Collect all keys from flattened objects:
- From first object:
["name", "age"]
- From second object:
["name", "details.age", "details.city"]
- Unique keys:
["name", "age", "details.age", "details.city"]
- Sorted:
["age", "details.age", "details.city", "name"]
Step 3: Build the matrix
Start with headers:
[["age", "details.age", "details.city", "name"]]
For first object's row:
age
: found →30
details.age
: not found →""
details.city
: not found →""
name
: found →"Alice"
- Row:
[30, "", "", "Alice"]
For second object's row:
age
: not found →""
details.age
: found →25
details.city
: found →"NYC"
name
: found →"Bob"
- Row:
["", 25, "NYC", "Bob"]
Final Output:
[ ["age", "details.age", "details.city", "name"], [30, "", "", "Alice"], ["", 25, "NYC", "Bob"] ]
The matrix successfully represents both objects with a consistent column structure, filling in empty strings where values don't exist.
Solution Implementation
1def jsonToMatrix(arr):
2 """
3 Converts an array of JSON objects into a matrix format with flattened keys
4
5 Args:
6 arr: List of dictionaries to be converted into matrix format
7
8 Returns:
9 Matrix where first row contains sorted column headers and subsequent rows contain values
10 """
11
12 def flatten_object(key, obj):
13 """
14 Recursively flattens nested objects into key-value pairs with dot notation
15
16 Args:
17 key: Current key path (e.g., "parent.child")
18 obj: Current object or value being processed
19
20 Returns:
21 Flattened dictionary(s) with dot-notation keys
22 """
23 # Base case: primitive values or None
24 if (isinstance(obj, (int, float, str, bool)) or obj is None):
25 return {key: obj}
26
27 # Recursive case: process nested dictionaries
28 flattened = []
29 for property_key, property_value in obj.items():
30 # Build new key path with dot notation
31 new_key_path = f"{key}.{property_key}" if key else property_key
32 result = flatten_object(new_key_path, property_value)
33
34 # Handle both single dict and list of dicts
35 if isinstance(result, list):
36 flattened.extend(result)
37 else:
38 flattened.append(result)
39
40 # Return flattened list of dictionaries
41 return flattened
42
43 # Convert each object in the array to flattened key-value pairs
44 flattened_rows = []
45 for obj in arr:
46 flattened = flatten_object('', obj)
47 # Ensure result is always a list
48 if isinstance(flattened, dict):
49 flattened_rows.append([flattened])
50 else:
51 flattened_rows.append(flattened)
52
53 # Extract all unique keys from flattened objects and sort them
54 unique_keys_set = set()
55 for flattened_row in flattened_rows:
56 for flat_object in flattened_row:
57 unique_keys_set.update(flat_object.keys())
58
59 unique_keys = sorted(list(unique_keys_set))
60
61 # Build the result matrix with headers as first row
62 result_matrix = [unique_keys]
63
64 # Process each row to align values with column headers
65 for flattened_row in flattened_rows:
66 matrix_row = []
67
68 for column_key in unique_keys:
69 # Find the object containing the current key
70 matching_object = None
71 for flat_object in flattened_row:
72 if column_key in flat_object:
73 matching_object = flat_object
74 break
75
76 # Extract value or use empty string if key doesn't exist
77 if matching_object and column_key in matching_object:
78 cell_value = matching_object[column_key]
79 else:
80 cell_value = ''
81
82 matrix_row.append(cell_value)
83
84 result_matrix.append(matrix_row)
85
86 return result_matrix
87
1import java.util.*;
2import java.util.stream.Collectors;
3
4public class JsonToMatrixConverter {
5
6 /**
7 * Converts an array of JSON objects into a matrix format with flattened keys
8 * @param arr - List of maps representing JSON objects to be converted into matrix format
9 * @return Matrix where first row contains sorted column headers and subsequent rows contain values
10 */
11 public static List<List<Object>> jsonToMatrix(List<Map<String, Object>> arr) {
12 // Convert each object in the array to flattened key-value pairs
13 List<List<Map<String, Object>>> flattenedRows = new ArrayList<>();
14 for (Map<String, Object> object : arr) {
15 flattenedRows.add(flattenObject("", object));
16 }
17
18 // Extract all unique keys from flattened objects and sort them
19 Set<String> uniqueKeysSet = new TreeSet<>(); // TreeSet maintains sorted order
20 for (List<Map<String, Object>> flattenedRow : flattenedRows) {
21 for (Map<String, Object> flatObject : flattenedRow) {
22 uniqueKeysSet.addAll(flatObject.keySet());
23 }
24 }
25 List<String> uniqueKeys = new ArrayList<>(uniqueKeysSet);
26
27 // Build the result matrix with headers as first row
28 List<List<Object>> resultMatrix = new ArrayList<>();
29 // Add header row
30 resultMatrix.add(new ArrayList<>(uniqueKeys));
31
32 // Process each row to align values with column headers
33 for (List<Map<String, Object>> flattenedRow : flattenedRows) {
34 List<Object> matrixRow = new ArrayList<>();
35
36 for (String columnKey : uniqueKeys) {
37 // Find the object containing the current key
38 Map<String, Object> matchingObject = null;
39 for (Map<String, Object> flatObject : flattenedRow) {
40 if (flatObject.containsKey(columnKey)) {
41 matchingObject = flatObject;
42 break;
43 }
44 }
45
46 // Extract value or use empty string if key doesn't exist
47 Object cellValue = matchingObject != null ? matchingObject.get(columnKey) : "";
48 matrixRow.add(cellValue);
49 }
50
51 resultMatrix.add(matrixRow);
52 }
53
54 return resultMatrix;
55 }
56
57 /**
58 * Recursively flattens nested objects into key-value pairs with dot notation
59 * @param key - Current key path (e.g., "parent.child")
60 * @param obj - Current object or value being processed
61 * @return List of flattened objects with dot-notation keys
62 */
63 private static List<Map<String, Object>> flattenObject(String key, Object obj) {
64 // Base case: primitive values or null
65 if (obj == null ||
66 obj instanceof Number ||
67 obj instanceof String ||
68 obj instanceof Boolean) {
69 // Return single map with the key-value pair
70 Map<String, Object> result = new HashMap<>();
71 result.put(key, obj);
72 return Arrays.asList(result);
73 }
74
75 // Recursive case: process nested objects (Map)
76 if (obj instanceof Map) {
77 List<Map<String, Object>> flattened = new ArrayList<>();
78 Map<String, Object> mapObj = (Map<String, Object>) obj;
79
80 for (Map.Entry<String, Object> entry : mapObj.entrySet()) {
81 String propertyKey = entry.getKey();
82 Object propertyValue = entry.getValue();
83
84 // Build new key path with dot notation
85 String newKeyPath = key.isEmpty() ? propertyKey : key + "." + propertyKey;
86
87 // Recursively flatten and add all results
88 flattened.addAll(flattenObject(newKeyPath, propertyValue));
89 }
90
91 return flattened;
92 }
93
94 // Handle unexpected types by returning empty list
95 return new ArrayList<>();
96 }
97}
98
1#include <vector>
2#include <string>
3#include <unordered_map>
4#include <set>
5#include <algorithm>
6#include <variant>
7#include <memory>
8
9using namespace std;
10
11// Define a variant type to hold different JSON value types
12using JsonValue = variant<nullptr_t, bool, int, double, string>;
13
14// Define a JSON object as a map of string keys to either values or nested objects
15class JsonObject {
16public:
17 unordered_map<string, variant<JsonValue, shared_ptr<JsonObject>>> data;
18};
19
20/**
21 * Converts an array of JSON objects into a matrix format with flattened keys
22 * @param arr - Array of objects to be converted into matrix format
23 * @returns Matrix where first row contains sorted column headers and subsequent rows contain values
24 */
25vector<vector<variant<string, int, double, bool, nullptr_t>>> jsonToMatrix(vector<shared_ptr<JsonObject>> arr) {
26 // Type alias for the flattened key-value pairs
27 using FlattenedObject = unordered_map<string, JsonValue>;
28
29 /**
30 * Recursively flattens nested objects into key-value pairs with dot notation
31 * @param key - Current key path (e.g., "parent.child")
32 * @param obj - Current object or value being processed
33 * @returns Flattened object(s) with dot-notation keys
34 */
35 auto flattenObject = [](const string& key, const variant<JsonValue, shared_ptr<JsonObject>>& obj) -> vector<FlattenedObject> {
36 // Lambda for recursive flattening
37 function<vector<FlattenedObject>(const string&, const variant<JsonValue, shared_ptr<JsonObject>>&)> flatten;
38
39 flatten = [&flatten](const string& currentKey, const variant<JsonValue, shared_ptr<JsonObject>>& currentObj) -> vector<FlattenedObject> {
40 // Check if it's a primitive value or null
41 if (holds_alternative<JsonValue>(currentObj)) {
42 FlattenedObject result;
43 result[currentKey] = get<JsonValue>(currentObj);
44 return {result};
45 }
46
47 // Process nested object
48 vector<FlattenedObject> flattened;
49 auto jsonObj = get<shared_ptr<JsonObject>>(currentObj);
50
51 for (const auto& [propertyKey, propertyValue] : jsonObj->data) {
52 // Build new key path with dot notation
53 string newKeyPath = currentKey.empty() ? propertyKey : currentKey + "." + propertyKey;
54
55 // Recursively flatten and collect results
56 auto nestedResults = flatten(newKeyPath, propertyValue);
57 flattened.insert(flattened.end(), nestedResults.begin(), nestedResults.end());
58 }
59
60 // Merge all flattened objects into a single level
61 if (flattened.empty()) {
62 return {FlattenedObject()};
63 }
64
65 FlattenedObject merged;
66 for (const auto& flatObj : flattened) {
67 for (const auto& [k, v] : flatObj) {
68 merged[k] = v;
69 }
70 }
71 return {merged};
72 };
73
74 return flatten(key, obj);
75 };
76
77 // Convert each object in the array to flattened key-value pairs
78 vector<vector<FlattenedObject>> flattenedRows;
79 for (const auto& object : arr) {
80 variant<JsonValue, shared_ptr<JsonObject>> objVariant = object;
81 flattenedRows.push_back(flattenObject("", objVariant));
82 }
83
84 // Extract all unique keys from flattened objects
85 set<string> uniqueKeysSet;
86 for (const auto& row : flattenedRows) {
87 for (const auto& flatObj : row) {
88 for (const auto& [key, value] : flatObj) {
89 uniqueKeysSet.insert(key);
90 }
91 }
92 }
93
94 // Convert set to sorted vector
95 vector<string> uniqueKeys(uniqueKeysSet.begin(), uniqueKeysSet.end());
96 sort(uniqueKeys.begin(), uniqueKeys.end());
97
98 // Build the result matrix with headers as first row
99 vector<vector<variant<string, int, double, bool, nullptr_t>>> resultMatrix;
100
101 // Add header row
102 vector<variant<string, int, double, bool, nullptr_t>> headerRow;
103 for (const auto& key : uniqueKeys) {
104 headerRow.push_back(key);
105 }
106 resultMatrix.push_back(headerRow);
107
108 // Process each row to align values with column headers
109 for (const auto& flattenedRow : flattenedRows) {
110 vector<variant<string, int, double, bool, nullptr_t>> matrixRow;
111
112 // Merge all flattened objects in the row
113 FlattenedObject mergedRow;
114 for (const auto& flatObj : flattenedRow) {
115 for (const auto& [k, v] : flatObj) {
116 mergedRow[k] = v;
117 }
118 }
119
120 // Fill values for each column
121 for (const auto& columnKey : uniqueKeys) {
122 // Find if the current key exists in the merged row
123 if (mergedRow.find(columnKey) != mergedRow.end()) {
124 // Convert JsonValue to the appropriate variant type
125 JsonValue val = mergedRow[columnKey];
126 if (holds_alternative<nullptr_t>(val)) {
127 matrixRow.push_back(nullptr);
128 } else if (holds_alternative<bool>(val)) {
129 matrixRow.push_back(get<bool>(val));
130 } else if (holds_alternative<int>(val)) {
131 matrixRow.push_back(get<int>(val));
132 } else if (holds_alternative<double>(val)) {
133 matrixRow.push_back(get<double>(val));
134 } else if (holds_alternative<string>(val)) {
135 matrixRow.push_back(get<string>(val));
136 }
137 } else {
138 // Use empty string if key doesn't exist
139 matrixRow.push_back(string(""));
140 }
141 }
142
143 resultMatrix.push_back(matrixRow);
144 }
145
146 return resultMatrix;
147}
148
1/**
2 * Converts an array of JSON objects into a matrix format with flattened keys
3 * @param arr - Array of objects to be converted into matrix format
4 * @returns Matrix where first row contains sorted column headers and subsequent rows contain values
5 */
6function jsonToMatrix(arr: any[]): (string | number | boolean | null)[][] {
7 /**
8 * Recursively flattens nested objects into key-value pairs with dot notation
9 * @param key - Current key path (e.g., "parent.child")
10 * @param obj - Current object or value being processed
11 * @returns Flattened object(s) with dot-notation keys
12 */
13 const flattenObject = (key: string, obj: any): any => {
14 // Base case: primitive values or null
15 if (
16 typeof obj === 'number' ||
17 typeof obj === 'string' ||
18 typeof obj === 'boolean' ||
19 obj === null
20 ) {
21 return { [key]: obj };
22 }
23
24 // Recursive case: process nested objects
25 const flattened: any[] = [];
26 for (const [propertyKey, propertyValue] of Object.entries(obj)) {
27 // Build new key path with dot notation
28 const newKeyPath = key ? `${key}.${propertyKey}` : propertyKey;
29 flattened.push(flattenObject(newKeyPath, propertyValue));
30 }
31
32 // Flatten array of results into single level
33 return flattened.flat();
34 };
35
36 // Convert each object in the array to flattened key-value pairs
37 const flattenedRows = arr.map(object => flattenObject('', object));
38
39 // Extract all unique keys from flattened objects and sort them
40 const uniqueKeys = [
41 ...new Set(
42 flattenedRows
43 .flat()
44 .map(flatObject => Object.keys(flatObject))
45 .flat()
46 )
47 ].sort();
48
49 // Build the result matrix with headers as first row
50 const resultMatrix: any[][] = [uniqueKeys];
51
52 // Process each row to align values with column headers
53 for (const flattenedRow of flattenedRows) {
54 const matrixRow: any[] = [];
55
56 for (const columnKey of uniqueKeys) {
57 // Find the object containing the current key
58 const matchingObject = flattenedRow.find(
59 flatObject => flatObject.hasOwnProperty(columnKey)
60 );
61
62 // Extract value or use empty string if key doesn't exist
63 const cellValue = matchingObject?.[columnKey];
64 matrixRow.push(cellValue === undefined ? '' : cellValue);
65 }
66
67 resultMatrix.push(matrixRow);
68 }
69
70 return resultMatrix;
71}
72
Time and Space Complexity
Time Complexity: O(n * m * d + n * k^2)
Where:
n
= number of objects in the input arraym
= average number of key-value pairs per object (including nested)d
= maximum depth of nestingk
= total number of unique keys across all objects
Breaking down the operations:
- The
dfs
function traverses each object recursively:O(m * d)
per object - Mapping
dfs
over all objects:O(n * m * d)
- Extracting and deduplicating keys:
O(n * m)
for extraction,O(k log k)
for sorting - Building the result matrix:
O(n * k)
iterations, with each iteration doing afind
operation that costsO(k)
in worst case
The dominant term is O(n * k^2)
from the nested loop with the find
operation, though in practice if objects are sparse, this could be closer to O(n * m * d + n * k)
.
Space Complexity: O(n * m * d + k)
Where the space is used for:
- Recursive call stack for
dfs
:O(d)
maximum depth - Flattened key-value pairs stored in
kv
:O(n * m)
total pairs - Unique keys array:
O(k)
- Result matrix:
O(n * k)
for the final answer
The dominant term is O(n * k)
for storing the final matrix, though the intermediate storage of flattened objects also contributes significantly as O(n * m)
.
Common Pitfalls
1. Incorrect Handling of Array Elements Within Objects
One major pitfall is not properly handling arrays that appear as values within objects. The current implementation treats arrays like objects (iterating over their indices as keys), which creates column names like "items.0"
, "items.1"
, etc., instead of properly handling array elements.
Problem Example:
arr = [ {"id": 1, "items": ["a", "b"]}, {"id": 2, "items": ["c", "d", "e"]} ]
Current output would create columns: ["id", "items.0", "items.1", "items.2"]
Solution: Add explicit array detection and handling:
def flatten_object(key, obj):
# Handle arrays differently from objects
if isinstance(obj, list):
flattened = []
for index, item in enumerate(obj):
new_key_path = f"{key}.{index}" if key else str(index)
result = flatten_object(new_key_path, item)
if isinstance(result, list):
flattened.extend(result)
else:
flattened.append(result)
return flattened
# Handle dictionaries
if isinstance(obj, dict):
flattened = []
for property_key, property_value in obj.items():
new_key_path = f"{key}.{property_key}" if key else property_key
result = flatten_object(new_key_path, property_value)
if isinstance(result, list):
flattened.extend(result)
else:
flattened.append(result)
return flattened
# Base case: primitive values
return {key: obj}
2. Loss of Data When Multiple Values Map to Same Key
When flattening nested structures, if an object contains both a value and nested properties at the same level, data can be lost because the flattened representation can't distinguish between them.
Problem Example:
arr = [ {"a": {"b": 1, "c": {"d": 2}}}, {"a": {"b": 3, "c": 4}} # 'c' is sometimes a value, sometimes an object ]
This creates inconsistent structures where "a.c"
and "a.c.d"
both exist, but "a.c"
might be overwritten.
Solution: Implement validation or use a merging strategy:
def flatten_object(key, obj, flattened_dict=None):
if flattened_dict is None:
flattened_dict = {}
if isinstance(obj, dict):
for k, v in obj.items():
new_key = f"{key}.{k}" if key else k
flatten_object(new_key, v, flattened_dict)
elif isinstance(obj, list):
for i, item in enumerate(obj):
new_key = f"{key}.{i}" if key else str(i)
flatten_object(new_key, item, flattened_dict)
else:
# Check for conflicts before assignment
if key in flattened_dict:
# Handle conflict (could log, merge, or raise error)
pass
flattened_dict[key] = obj
return flattened_dict
3. Memory Inefficiency with Deep Nesting
The recursive approach with list concatenation (extend()
and append()
) creates many intermediate lists, which can be memory-intensive for deeply nested structures.
Solution: Use a single accumulator dictionary passed through recursion:
def jsonToMatrix(arr):
def flatten_object(obj, prefix='', result=None):
if result is None:
result = {}
if isinstance(obj, dict):
for key, value in obj.items():
new_key = f"{prefix}.{key}" if prefix else key
if isinstance(value, (dict, list)):
flatten_object(value, new_key, result)
else:
result[new_key] = value
elif isinstance(obj, list):
for i, item in enumerate(obj):
new_key = f"{prefix}.{i}" if prefix else str(i)
if isinstance(item, (dict, list)):
flatten_object(item, new_key, result)
else:
result[new_key] = item
else:
result[prefix] = obj
return result
# Flatten all objects
flattened_rows = [flatten_object(obj) for obj in arr]
# Get unique keys
all_keys = set()
for row in flattened_rows:
all_keys.update(row.keys())
sorted_keys = sorted(all_keys)
# Build matrix
matrix = [sorted_keys]
for row in flattened_rows:
matrix.append([row.get(key, '') for key in sorted_keys])
return matrix
This approach uses a single dictionary per object instead of lists of dictionaries, significantly reducing memory overhead and improving performance.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
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!