-
-
Save Xunnamius/e31e791ad7cf462eee9ac175a0e094bb to your computer and use it in GitHub Desktop.
// @ts-check | |
// This problem statement was fun. It can be deceptively difficult if you aren't | |
// aware of some of the footguns and gotchas of the JS language. | |
// | |
// This problem requires several questions to be asked / assumptions to be made: | |
// | |
// I. Seems like they're not using the word "object" in the way ECMA does. They | |
// differentiate between "object" and "array" even though arrays are objects. | |
// This leads to assumption #1: "object" and "objects" in the problem | |
// statement refers to "records" (i.e. plain {} objects) ONLY and nothing | |
// else. Given the "preserve original data structure" constraint, this means | |
// don't use maps. Not that we need to here; all non-extinct JavaScript | |
// engines will essentially preserve the insertion order of object entries. | |
// | |
// II. I would ask if they want all constraints to apply recursively to, e.g., | |
// objects within arrays within objects and what not. I completed the | |
// non-recursive version in ~10 minutes total. For a challenge, I refactored | |
// it into a recursive version in ~30 minutes total. This includes | |
// comments/types. Assumption #2: constraints on array contents and object | |
// entry order apply recursively to the contents of arrays and objects. | |
// | |
// III. I would ask if the current shape of the JSON input is the expected | |
// shape. Essentially, I'd want a gauge of how likely the data is to change | |
// shape, and how, and/or if there's some contract/spec we're operating off | |
// of. So we assume the worst. Assumption #3: the API we're accessing might | |
// return **ANY** **valid** JSON (including stuff like `"just a string"`). | |
// | |
// IV. I would ask if the line "remove any object properties with all values set | |
// to [nullish/empty]" should be considered recursively or not. Assumption #4: | |
// an array (which is NOT an "object" in the context of this problem | |
// statement) with empty elements (which are technically its properties) | |
// should not have those elements removed. Only an "object" entry with a | |
// nullish/empty value should be deleted. So, for example, the object `{ | |
// empty: '' }` becomes `{}` but `{ empty: [''] }` is unchanged. This is | |
// arguable since it also says "with all values set" even though a property | |
// only has one value; needs clarification. | |
// | |
// V. This is a corollary to IV: assumption #5: the word "objects" in "remove | |
// duplicate objects from arrays" is referring ONLY to records. Duplicate | |
// non-"objects" in arrays should be left alone. So, for example, the object | |
// `{ empty: '' }` becomes `{}` but `{ empty: ['', ''] }` is unchanged. | |
// Feels good to be in the future | |
const alphasort = new Intl.Collator(undefined, { | |
numeric: true, | |
sensitivity: 'base' | |
}).compare; | |
const response = await fetch( | |
'https://coderbyte.com/api/challenges/json/wizard-list' | |
); | |
/** | |
* @type {unknown} | |
*/ | |
const wizards = await response.json(); | |
console.log(JSON.stringify(sanitize(wizards), undefined, 2)); | |
// *** | |
/** | |
* If `target` is an array, a new array is returned with `sanitize` called on | |
* each element of `target`. If `target` is an object, {@link sanitizeObject} is | |
* called on it and the result returned. Otherwise, `target` is returned as-is. | |
*/ | |
function sanitize(/** @type {unknown} */ target) { | |
if (Array.isArray(target)) { | |
const updatedTargets = []; | |
for (const value of target.values()) { | |
const sanitized = sanitize(value); | |
if (!isRecord(sanitized) || !isInArray(updatedTargets, sanitized)) { | |
updatedTargets.push(sanitized); | |
} | |
} | |
return updatedTargets; | |
} | |
// Otherwise, if it's just a normal object | |
else if (isRecord(target)) { | |
return sanitizeObject(target); | |
} else { | |
return target; | |
} | |
} | |
function sanitizeObject(/** @type {Record<PropertyKey, unknown>} */ obj) { | |
const entries = Object.entries(obj); | |
const nonEmptyEntries = excludeEmptyEntries(entries); | |
const sortedObj = alphasortRecordEntries(obj, nonEmptyEntries); | |
for (const [key, value] of nonEmptyEntries) { | |
sortedObj[key.toString()] = sanitize(value); | |
} | |
return sortedObj; | |
} | |
function excludeEmptyEntries(/** @type {[PropertyKey, unknown][]} */ entries) { | |
return entries.filter( | |
([, value]) => !(value === '' || value === null || value === undefined) | |
); | |
} | |
/** | |
* @returns {Record<string, unknown>} | |
*/ | |
function alphasortRecordEntries( | |
/** @type {Record<PropertyKey, unknown>} */ record, | |
/** @type {[PropertyKey, unknown][]} */ entries | |
) { | |
const sortedKeys = entries.map(([key]) => key.toString()).sort(alphasort); | |
return Object.fromEntries(sortedKeys.map((key) => [key, record[key]])); | |
} | |
/** | |
* Returns `true` if a `needle` record loosely equals a record in `haystack`. | |
*/ | |
function isInArray( | |
/** @type {Record<PropertyKey, unknown>[]} */ haystack, | |
/** @type {Record<PropertyKey, unknown>} */ needle | |
) { | |
const stringifiedNeedle = JSON.stringify(needle); | |
// TODO: this shortcut is okay for small JSON objects w/ sorted keys, but not | |
// TODO: efficient for larger objects or a haystack of many small objects and | |
// TODO: should be refactored using .hasOwn (better: use a lib like lodash) | |
return haystack.some((item) => JSON.stringify(item) === stringifiedNeedle); | |
} | |
/** | |
* | |
* @returns {target is Record<PropertyKey, unknown>} | |
*/ | |
function isRecord(/** @type {unknown} */ target) { | |
return !!target && typeof target === 'object'; | |
} |
[ | |
{ | |
"name": "HarryPotter", | |
"age": 18, | |
"house": "", | |
"wand": { | |
"wood": "Holly", | |
"core": "Phoenixfeather", | |
"length": 11 | |
}, | |
"friends": [ | |
{ | |
"name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Vine", | |
"core": "Dragonheartstring", | |
"length": 10.75 | |
}, | |
"occupation": null | |
}, | |
{ | |
"name": "RonWeasley", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Willow", | |
"core": "Unicornhair", | |
"length": 14 | |
}, | |
"occupation": "student" | |
}, | |
{ | |
"name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Vine", | |
"core": "Dragonheartstring", | |
"length": 10.75 | |
}, | |
"occupation": null | |
} | |
], | |
"enemies": ["LordVoldemort", "DracoMalfoy"], | |
"patronus": "Stag" | |
}, | |
{ | |
"name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "", | |
"core": "", | |
"length": null | |
}, | |
"friends": [ | |
{ | |
"name": "HarryPotter", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Holly", | |
"core": "Phoenixfeather", | |
"length": 11 | |
}, | |
"occupation": "student" | |
}, | |
{ | |
"name": "RonWeasley", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Willow", | |
"core": "Unicornhair", | |
"length": 14 | |
}, | |
"occupation": "student" | |
}, | |
{ | |
"name": "LunaLovegood", | |
"age": 18, | |
"house": "Ravenclaw", | |
"wand": { | |
"wood": "Unknown", | |
"core": "Unknown", | |
"length": "Unknown" | |
}, | |
"occupation": "student" | |
} | |
], | |
"enemies": ["", ""], | |
"patronus": "Otter" | |
}, | |
{ | |
"name": "RonWeasley", | |
"age": 18, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Willow", | |
"core": "Unicornhair", | |
"length": 14 | |
}, | |
"friends": [ | |
{ | |
"name": "HarryPotter", | |
"age": 18, | |
"house": "" | |
}, | |
{ | |
"name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor" | |
}, | |
{ | |
"name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor" | |
} | |
], | |
"enemies": [ | |
{ | |
"name": "DracoMalfoy", | |
"age": 18, | |
"house": "Slytherin" | |
}, | |
{ | |
"name": "VincentCrabbe", | |
"age": 18, | |
"house": "Slytherin" | |
} | |
], | |
"patronus": "JackRussellTerrier" | |
}, | |
{ | |
"name": "GinnyWeasley", | |
"age": null, | |
"house": "Gryffindor", | |
"wand": { | |
"wood": "Yew", | |
"core": "Phoenixfeather", | |
"length": 9 | |
}, | |
"friends": [ | |
{ | |
"name": "HarryPotter", | |
"age": 18, | |
"house": "Gryffindor", | |
"occupation": "Auror" | |
}, | |
{ | |
"name": "LunaLovegood", | |
"age": 17, | |
"house": "Ravenclaw", | |
"occupation": "Magizoologist" | |
}, | |
{ | |
"name": "NevilleLongbottom", | |
"age": 18, | |
"house": "Gryffindor", | |
"occupation": "ProfessorofHerbology" | |
} | |
], | |
"enemies": [ | |
{ | |
"name": "TomRiddle", | |
"alias": "LordVoldemort" | |
}, | |
{ | |
"name": "BellatrixLestrange", | |
"alias": "Bella" | |
} | |
], | |
"patronus": "Horse" | |
}, | |
{ | |
"name": "DracoMalfoy", | |
"age": 18, | |
"house": "Slytherin", | |
"wand": { | |
"wood": "Hawthorn", | |
"core": "Unicornhair", | |
"length": 10 | |
}, | |
"friends": [ | |
{ | |
"name": "VincentCrabbe", | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
"occupation": null | |
}, | |
{ | |
"name": "GregoryGoyle", | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
"occupation": null | |
} | |
], | |
"enemies": [ | |
{ | |
"name": "HarryPotter", | |
"age": 17, | |
"house": "Gryffindor", | |
"occupation": null | |
}, | |
{ | |
"name": "HermioneGranger", | |
"age": 17, | |
"house": "Gryffindor", | |
"occupation": null | |
}, | |
{ | |
"name": "RonWeasley", | |
"age": 17, | |
"house": "Gryffindor", | |
"occupation": null | |
} | |
], | |
"patronus": null | |
} | |
] |
[ | |
{ | |
"age": 18, | |
"enemies": ["LordVoldemort", "DracoMalfoy"], | |
"friends": [ | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "HermioneGranger", | |
"wand": { | |
"core": "Dragonheartstring", | |
"length": 10.75, | |
"wood": "Vine" | |
} | |
}, | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "RonWeasley", | |
"occupation": "student", | |
"wand": { | |
"core": "Unicornhair", | |
"length": 14, | |
"wood": "Willow" | |
} | |
} | |
], | |
"name": "HarryPotter", | |
"patronus": "Stag", | |
"wand": { | |
"core": "Phoenixfeather", | |
"length": 11, | |
"wood": "Holly" | |
} | |
}, | |
{ | |
"age": 18, | |
"enemies": ["", ""], | |
"friends": [ | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "HarryPotter", | |
"occupation": "student", | |
"wand": { | |
"core": "Phoenixfeather", | |
"length": 11, | |
"wood": "Holly" | |
} | |
}, | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "RonWeasley", | |
"occupation": "student", | |
"wand": { | |
"core": "Unicornhair", | |
"length": 14, | |
"wood": "Willow" | |
} | |
}, | |
{ | |
"age": 18, | |
"house": "Ravenclaw", | |
"name": "LunaLovegood", | |
"occupation": "student", | |
"wand": { | |
"core": "Unknown", | |
"length": "Unknown", | |
"wood": "Unknown" | |
} | |
} | |
], | |
"house": "Gryffindor", | |
"name": "HermioneGranger", | |
"patronus": "Otter", | |
"wand": {} | |
}, | |
{ | |
"age": 18, | |
"enemies": [ | |
{ | |
"age": 18, | |
"house": "Slytherin", | |
"name": "DracoMalfoy" | |
}, | |
{ | |
"age": 18, | |
"house": "Slytherin", | |
"name": "VincentCrabbe" | |
} | |
], | |
"friends": [ | |
{ | |
"age": 18, | |
"name": "HarryPotter" | |
}, | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "HermioneGranger" | |
} | |
], | |
"house": "Gryffindor", | |
"name": "RonWeasley", | |
"patronus": "JackRussellTerrier", | |
"wand": { | |
"core": "Unicornhair", | |
"length": 14, | |
"wood": "Willow" | |
} | |
}, | |
{ | |
"enemies": [ | |
{ | |
"alias": "LordVoldemort", | |
"name": "TomRiddle" | |
}, | |
{ | |
"alias": "Bella", | |
"name": "BellatrixLestrange" | |
} | |
], | |
"friends": [ | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "HarryPotter", | |
"occupation": "Auror" | |
}, | |
{ | |
"age": 17, | |
"house": "Ravenclaw", | |
"name": "LunaLovegood", | |
"occupation": "Magizoologist" | |
}, | |
{ | |
"age": 18, | |
"house": "Gryffindor", | |
"name": "NevilleLongbottom", | |
"occupation": "ProfessorofHerbology" | |
} | |
], | |
"house": "Gryffindor", | |
"name": "GinnyWeasley", | |
"patronus": "Horse", | |
"wand": { | |
"core": "Phoenixfeather", | |
"length": 9, | |
"wood": "Yew" | |
} | |
}, | |
{ | |
"age": 18, | |
"enemies": [ | |
{ | |
"age": 17, | |
"house": "Gryffindor", | |
"name": "HarryPotter" | |
}, | |
{ | |
"age": 17, | |
"house": "Gryffindor", | |
"name": "HermioneGranger" | |
}, | |
{ | |
"age": 17, | |
"house": "Gryffindor", | |
"name": "RonWeasley" | |
} | |
], | |
"friends": [ | |
{ | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
"name": "VincentCrabbe" | |
}, | |
{ | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
"name": "GregoryGoyle" | |
} | |
], | |
"house": "Slytherin", | |
"name": "DracoMalfoy", | |
"wand": { | |
"core": "Unicornhair", | |
"length": 10, | |
"wood": "Hawthorn" | |
} | |
} | |
] |
--- x-input.json 2025-05-20 05:09:59.766813931 -0700 | |
+++ x-output.json 2025-05-20 05:09:54.493551616 -0700 | |
@@ -1,224 +1,194 @@ | |
[ | |
{ | |
- "name": "HarryPotter", | |
"age": 18, | |
- "house": "", | |
- "wand": { | |
- "wood": "Holly", | |
- "core": "Phoenixfeather", | |
- "length": 11 | |
- }, | |
+ "enemies": ["LordVoldemort", "DracoMalfoy"], | |
"friends": [ | |
{ | |
- "name": "HermioneGranger", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "HermioneGranger", | |
"wand": { | |
- "wood": "Vine", | |
"core": "Dragonheartstring", | |
- "length": 10.75 | |
- }, | |
- "occupation": null | |
+ "length": 10.75, | |
+ "wood": "Vine" | |
+ } | |
}, | |
{ | |
- "name": "RonWeasley", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "RonWeasley", | |
+ "occupation": "student", | |
"wand": { | |
- "wood": "Willow", | |
"core": "Unicornhair", | |
- "length": 14 | |
- }, | |
- "occupation": "student" | |
- }, | |
- { | |
- "name": "HermioneGranger", | |
- "age": 18, | |
- "house": "Gryffindor", | |
- "wand": { | |
- "wood": "Vine", | |
- "core": "Dragonheartstring", | |
- "length": 10.75 | |
- }, | |
- "occupation": null | |
+ "length": 14, | |
+ "wood": "Willow" | |
+ } | |
} | |
], | |
- "enemies": ["LordVoldemort", "DracoMalfoy"], | |
- "patronus": "Stag" | |
+ "name": "HarryPotter", | |
+ "patronus": "Stag", | |
+ "wand": { | |
+ "core": "Phoenixfeather", | |
+ "length": 11, | |
+ "wood": "Holly" | |
+ } | |
}, | |
{ | |
- "name": "HermioneGranger", | |
"age": 18, | |
- "house": "Gryffindor", | |
- "wand": { | |
- "wood": "", | |
- "core": "", | |
- "length": null | |
- }, | |
+ "enemies": ["", ""], | |
"friends": [ | |
{ | |
- "name": "HarryPotter", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "HarryPotter", | |
+ "occupation": "student", | |
"wand": { | |
- "wood": "Holly", | |
"core": "Phoenixfeather", | |
- "length": 11 | |
- }, | |
- "occupation": "student" | |
+ "length": 11, | |
+ "wood": "Holly" | |
+ } | |
}, | |
{ | |
- "name": "RonWeasley", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "RonWeasley", | |
+ "occupation": "student", | |
"wand": { | |
- "wood": "Willow", | |
"core": "Unicornhair", | |
- "length": 14 | |
- }, | |
- "occupation": "student" | |
+ "length": 14, | |
+ "wood": "Willow" | |
+ } | |
}, | |
{ | |
- "name": "LunaLovegood", | |
"age": 18, | |
"house": "Ravenclaw", | |
+ "name": "LunaLovegood", | |
+ "occupation": "student", | |
"wand": { | |
- "wood": "Unknown", | |
"core": "Unknown", | |
- "length": "Unknown" | |
- }, | |
- "occupation": "student" | |
+ "length": "Unknown", | |
+ "wood": "Unknown" | |
+ } | |
} | |
], | |
- "enemies": ["", ""], | |
- "patronus": "Otter" | |
+ "house": "Gryffindor", | |
+ "name": "HermioneGranger", | |
+ "patronus": "Otter", | |
+ "wand": {} | |
}, | |
{ | |
- "name": "RonWeasley", | |
"age": 18, | |
- "house": "Gryffindor", | |
- "wand": { | |
- "wood": "Willow", | |
- "core": "Unicornhair", | |
- "length": 14 | |
- }, | |
- "friends": [ | |
+ "enemies": [ | |
{ | |
- "name": "HarryPotter", | |
"age": 18, | |
- "house": "" | |
+ "house": "Slytherin", | |
+ "name": "DracoMalfoy" | |
}, | |
{ | |
- "name": "HermioneGranger", | |
"age": 18, | |
- "house": "Gryffindor" | |
- }, | |
- { | |
- "name": "HermioneGranger", | |
- "age": 18, | |
- "house": "Gryffindor" | |
+ "house": "Slytherin", | |
+ "name": "VincentCrabbe" | |
} | |
], | |
- "enemies": [ | |
+ "friends": [ | |
{ | |
- "name": "DracoMalfoy", | |
"age": 18, | |
- "house": "Slytherin" | |
+ "name": "HarryPotter" | |
}, | |
{ | |
- "name": "VincentCrabbe", | |
"age": 18, | |
- "house": "Slytherin" | |
+ "house": "Gryffindor", | |
+ "name": "HermioneGranger" | |
} | |
], | |
- "patronus": "JackRussellTerrier" | |
- }, | |
- { | |
- "name": "GinnyWeasley", | |
- "age": null, | |
"house": "Gryffindor", | |
+ "name": "RonWeasley", | |
+ "patronus": "JackRussellTerrier", | |
"wand": { | |
- "wood": "Yew", | |
- "core": "Phoenixfeather", | |
- "length": 9 | |
- }, | |
+ "core": "Unicornhair", | |
+ "length": 14, | |
+ "wood": "Willow" | |
+ } | |
+ }, | |
+ { | |
+ "enemies": [ | |
+ { | |
+ "alias": "LordVoldemort", | |
+ "name": "TomRiddle" | |
+ }, | |
+ { | |
+ "alias": "Bella", | |
+ "name": "BellatrixLestrange" | |
+ } | |
+ ], | |
"friends": [ | |
{ | |
- "name": "HarryPotter", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "HarryPotter", | |
"occupation": "Auror" | |
}, | |
{ | |
- "name": "LunaLovegood", | |
"age": 17, | |
"house": "Ravenclaw", | |
+ "name": "LunaLovegood", | |
"occupation": "Magizoologist" | |
}, | |
{ | |
- "name": "NevilleLongbottom", | |
"age": 18, | |
"house": "Gryffindor", | |
+ "name": "NevilleLongbottom", | |
"occupation": "ProfessorofHerbology" | |
} | |
], | |
+ "house": "Gryffindor", | |
+ "name": "GinnyWeasley", | |
+ "patronus": "Horse", | |
+ "wand": { | |
+ "core": "Phoenixfeather", | |
+ "length": 9, | |
+ "wood": "Yew" | |
+ } | |
+ }, | |
+ { | |
+ "age": 18, | |
"enemies": [ | |
{ | |
- "name": "TomRiddle", | |
- "alias": "LordVoldemort" | |
+ "age": 17, | |
+ "house": "Gryffindor", | |
+ "name": "HarryPotter" | |
+ }, | |
+ { | |
+ "age": 17, | |
+ "house": "Gryffindor", | |
+ "name": "HermioneGranger" | |
}, | |
{ | |
- "name": "BellatrixLestrange", | |
- "alias": "Bella" | |
+ "age": 17, | |
+ "house": "Gryffindor", | |
+ "name": "RonWeasley" | |
} | |
], | |
- "patronus": "Horse" | |
- }, | |
- { | |
- "name": "DracoMalfoy", | |
- "age": 18, | |
- "house": "Slytherin", | |
- "wand": { | |
- "wood": "Hawthorn", | |
- "core": "Unicornhair", | |
- "length": 10 | |
- }, | |
"friends": [ | |
{ | |
- "name": "VincentCrabbe", | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
- "occupation": null | |
+ "name": "VincentCrabbe" | |
}, | |
{ | |
- "name": "GregoryGoyle", | |
"age": 18, | |
"city": "England", | |
"country": "UK", | |
- "occupation": null | |
+ "name": "GregoryGoyle" | |
} | |
], | |
- "enemies": [ | |
- { | |
- "name": "HarryPotter", | |
- "age": 17, | |
- "house": "Gryffindor", | |
- "occupation": null | |
- }, | |
- { | |
- "name": "HermioneGranger", | |
- "age": 17, | |
- "house": "Gryffindor", | |
- "occupation": null | |
- }, | |
- { | |
- "name": "RonWeasley", | |
- "age": 17, | |
- "house": "Gryffindor", | |
- "occupation": null | |
- } | |
- ], | |
- "patronus": null | |
+ "house": "Slytherin", | |
+ "name": "DracoMalfoy", | |
+ "wand": { | |
+ "core": "Unicornhair", | |
+ "length": 10, | |
+ "wood": "Hawthorn" | |
+ } | |
} | |
] |
@mmkathurima Fair! It's definitely arguable, and is the reason I'm ambivalent on assumptions #4/5. Looking over it again, I am almost inclined to agree with you. What exactly was requested would have been cleared up with a question to the interviewer regardless 😄
The alternative functionality, where an array filled with empty elements is treated as "empty property values" (even though JSON object properties technically only have one value at a time) would be trivial to implement as a filter step at the end of the array handling logic of sanitize
, perhaps with special handling for an initial "empty" array. However, going in this direction also brings up the question of how to handle similarly "empty" records, which leads to "recursive emptiness" checks that can collapse and delete/exclude recursively "empty" data structures, which could be implemented by further tweaks to the tail end of the array and record logic of sanitize
at the risk of ballooning the solution.
At that point, we're dealing with a truly cursed data source.
In my solution, I skipped arrays of empty/null strings but included objects with empty property values.
An example is:
"wand": {
"wood": "",
"core": "",
"length": null
}
becomes
"wand": {}
For all this and some other tricky "situations", I have tried to follow the sample solution.
The only difference between my solution and yours is the array of empty strings.
I think the enemies property of the object with name "Hermione Granger" should not exist. Proof is in the statement
Further proof is in the sample test case (in the second screenshot of the Reddit post) where the
affiliations
property which is assigned to an array of 3 empty strings does not exist in the sample solution.