移除 JSON 对象中的数字值
问题描述
给定一个符合 JSON 格式的对象或数组 obj
,返回一个不包含数字值的新对象或数组。
这个新对象/数组与原始结构相同,但移除了所有值为 number
类型的键值对。这个操作需要递归地应用于所有嵌套的对象和数组。
注意:
- 数组被视为其索引是键的特殊对象。
- 完全由数字组成的字符串(例如
"123"
)不属于数字类型,应当被保留。 null
和undefined
值也应该被保留。
示例
示例 1:
- 输入:
obj = [null, 0, false, 1, "2"]
- 说明: 移除了索引
1
(值为0
) 和索引3
(值为1
)。 - 输出:
[null, false, "2"]
示例 2:
- 输入:
obj = {"a": 1, "b": [false, 1, "2"]}
- 说明: 移除了键
"a"
(值为1
)。在嵌套数组中,移除了值为1
的元素。 - 输出:
{ "b": [false, "2"]}
示例 3:
- 输入:
obj = [null, "0", 5, [0], [false, 16]]
- 说明: 移除了顶层的
5
。在第一个嵌套数组[0]
中移除了0
,使其变为空数组[]
。在第二个嵌套数组[false, 16]
中移除了16
。 - 输出:
[null, "0", [], [false]]
解题思路
解决这个问题的核心是编写一个递归函数,该函数能够处理三种情况:数组、对象和基本类型值。
基本情况(递归出口): 如果传入的值不是对象(即是字符串、布尔值、
null
、undefined
或数字),则直接返回该值。过滤操作将在调用它的上一层级中处理。处理数组: 如果传入的值是一个数组,我们创建一个新的空数组。然后遍历原数组的每一个元素,对每个元素进行递归调用。如果递归调用的返回值不是
number
类型,我们就将其添加到新数组中。处理对象: 如果传入的值是一个普通对象,我们创建一个新的空对象。然后遍历原对象的每一个键。对于每个键,我们检查其对应的值。如果值是
number
类型,我们就忽略这个键值对。否则,我们对该值进行递归调用,并将返回的结果以相同的键存入新对象中。
这种方法确保了我们能深入到任意层级的嵌套结构中,并正确地移除所有值为数字类型的元素或属性。
代码实现
/**
* 给定一个对象或数组 obj,它符合JSON的格式, 返回一个不包含数字值的对象。
* 不包含数字值的对象与原始对象相同,只是将包含数字类型的值的键移除。
* 该操作适用于对象及其嵌套对象。数组被视为索引作为键的对象。
* @param {any} obj - JSON-like object or array
* @returns {any} - a new object or array without numeric values
*/
function removeNumericValues(obj) {
// 处理数组
if (Array.isArray(obj)) {
const newArr = [];
for (const item of obj) {
// 如果值是数字,则跳过
if (typeof item === 'number') {
continue;
}
// 递归处理数组中的每一项
newArr.push(removeNumericValues(item));
}
return newArr;
}
// 处理对象 (但不是 null)
if (typeof obj === 'object' && obj !== null) {
const newObj = {};
for (const key in obj) {
const value = obj[key];
// 如果值是数字,则跳过
if (typeof value === 'number') {
continue;
}
// 递归处理对象中的每一个值
newObj[key] = removeNumericValues(value);
}
return newObj;
}
// 基本类型值直接返回
return obj;
}
// --- 测试用例 ---
// 示例 1
const obj1 = [null, undefined, 0, false, 1, '2'];
const output1 = removeNumericValues(obj1);
console.log('示例 1 输入:', JSON.stringify(obj1));
console.log('示例 1 输出:', JSON.stringify(output1)); // 预期: [null,undefined,false,"2"]
console.log('\n');
// 示例 2
const obj2 = { a: 1, b: [false, 1, '2'] };
const output2 = removeNumericValues(obj2);
console.log('示例 2 输入:', JSON.stringify(obj2));
console.log('示例 2 输出:', JSON.stringify(output2)); // 预期: {"b":[false,"2"]}
console.log('\n');
// 示例 3
const obj3 = [null, '0', 5, [0], [false, 16]];
const output3 = removeNumericValues(obj3);
console.log('示例 3 输入:', JSON.stringify(obj3));
console.log('示例 3 输出:', JSON.stringify(output3)); // 预期: [null,"0",[],[false]]
console.log('\n');
// 更多测试用例
const obj4 = {
id: 123,
user: 'test',
data: {
score: 100,
items: ['item1', 200, { rank: 1, valid: true }],
},
meta: null,
};
const output4 = removeNumericValues(obj4);
console.log('复杂对象输入:', JSON.stringify(obj4));
console.log('复杂对象输出:', JSON.stringify(output4)); // 预期: {"user":"test","data":{"items":["item1",{"valid":true}]},"meta":null}