JavaScript 从没有指定键的嵌套数组返回

Posted

技术标签:

【中文标题】JavaScript 从没有指定键的嵌套数组返回【英文标题】:JavaScript Return from Nested Array WITHOUT specified Keys 【发布时间】:2022-01-11 07:30:20 【问题描述】:

我正在尝试编写一个函数,该函数将从数组中可能嵌套的项中返回一个省略键的对象。我在另一个问题上找到了close answer,但不是我想要的。这是我现在正在修改的代码;

function omit(obj, keys) 
    let newObj = [];
    for (let i of obj) 
        if (i === keys) 
            //do nothing
         else 
            //newObj.push[i]; nope?
            return newObj;
        
        //return newObj;
    

编辑: 这是公式和一些示例输入/输出;

var x = 
    key1: true,
    key2: 2,
    key3: 
        nested1: 'javascript'
    
;

omit(x, ['key2', 'key3']) ==> 
    key1: true


omit(x, ['nested1']) ==> 
    key1: true,
    key2: 2,
    key3: ''

【问题讨论】:

您没有示例输入和输出数据,以及您的代码的一些实现,您不喜欢或不符合您的要求的输出呢? @PeterKA,我更新了我认为你的意思。对不起,对这一切还是很陌生。试图弄清楚在 tl;dr 免责声明之前要扔掉多少细节是必要的,哈哈 请看下面我的解决方案。 【参考方案1】:

所以,我对您的问题的解释是,您想要扫描数组中的值并返回没有它们的数组,但是您正在扫描的数组可能包含我们也想要检查的数组。我们不知道数组的格式以及它的深度。我们如何解决这个问题?答案是递归。首先,我们需要了解如何返回一个没有特定键的数组。所以让我们开始吧:

function omitFromArray(array, valuesToOmit) 
  const newArray = [] // we never reassign, use const
  for (const value of array)  // use const here as well, technically we make a new variable each iteration of the loop
    if (valuesToOmit.indexOf(value) === -1)  // if something doesn't exist in an array when we test for an index, it'll return -1
      newArray.push(value)
    
  
  return newArray // we want return to exist *outside* of the for loop so the for loop has a chance to run through all the required iterations;
                  // in your example, the return keyword is inside the for loop causing it to always give up after the first iteration


const arrayToTest = [1, 2, 3, 4, 5, 6]
const testValuesToOmit = [1, 4, 6]

console.log(omitFromArray(arrayToTest, testValuesToOmit))
// returns [2, 3, 5]

这很好用,但问题是它很浅;它只会扫描数组第一级中的值。为了解决这个问题,我们需要一个递归函数。下面是它的样子:

function omitFromNestedArray(array, valuesToOmit) 
  function walk(array, valuesToOmit)  // this is a modification of the function we wrote before
    const newArray = []
    for (const value of array) 
      if (Array.isArray(value))  // except now, we check if the current value happens to be another array
        newArray.push(walk(value, valuesToOmit)) // if it is, we actually call the function *inside itself* and return *its* value into our new array
       else 
        if (valuesToOmit.indexOf(value) === -1)  // if it's just a value, we can check it like normal
          newArray.push(value) // and put it in our array
        
      
    
    return newArray // and give it back at the very end
  
  return walk(array, valuesToOmit) // we finally need to call the function at the top level of our array and return that value


const nestedArrayToTest = [1, 2, [3, [4, 5], 6], 7]
const testValuesToOmit = [1, 4, 6]

console.log(omitFromNestedArray(nestedArrayToTest, testValuesToOmit))
// returns [2, [3, [5]], 7]

所以,递归函数的基本概念是函数调用自身。基本的“walk”函数做了我们通常忽略值的事情,但现在它检查我们是否遇到另一个数组;如果是的话,让我们暂停一下,先进入那个并通过它。我们一直这样做,直到我们到达最低级别,然后函数自然地开始循环往复,最终给我们一个新数组。如有任何问题,请追问!

编辑: 为了使代码适应对象而不是数组,我们这样做:

function removeUnwantedKeysFromObject(obj, unwantedKeys) 
  function walk(obj, unwantedKeys) 
    for (const key of Object.keys(obj))  // iterating through Object.keys(obj) will return each key in the object
      const value = obj[key] // we have to create a variable for the value this way
      if (typeof value === 'object')  // this is how we check if that value is another object
        walk(value, unwantedKeys)
       // we can't use else because we also want to delete this whole object if it's inside the keys we want to remove
      if (unwantedKeys.indexOf(key) !== -1)  // if it's just a value, we can check it like normal
        delete obj[key] // this is how you remove a key from an object
      
    
  
  walk(obj, unwantedKeys)


let objectToTest = key1: true, key2: 2, key3:  nested1: 'JavaScript' ;
removeUnwantedKeysFromObject(objectToTest, ['key2', 'key3'])
console.log(objectToTest)
// returns  key1: true 
objectToTest = key1: true, key2: 2, key3:  nested1: 'JavaScript' ;
removeUnwantedKeysFromObject(objectToTest, ['nested1'])
console.log(objectToTest)
// returns  key1: true, key2: 2, key3:  

我在这里有一个小警告:此代码编辑原始对象。如果您希望它构造一个新对象,则必须编辑代码以即时构造一个新对象,或使用库(例如 lodash)深度克隆原始对象并返回新对象。否则,这是相同的方法,但适用于对象而不是数组。

【讨论】:

我不得不通读几遍,但它似乎比我开始时更有意义。我敢肯定,更多的实验会让一切顺利。感谢您的帮助! @Alex 检查我所做的编辑,如果您需要更多关于如何使用对象的建议【参考方案2】:

下面演示中定义的omit()函数获取传递的对象的键,过滤掉要排除的键,然后根据剩下的键重建对象。

使用递归omit() 对这些剩余键的所有对象值运行。

const x = 
    key1: true,
    key2: 2,
    key3: 
        nested1: 'JavaScript'
    
;

const omit = ( obj, keys ) => obj.constructor.name === 'Object' && obj != null ? Object.keys(obj).filter(k => !keys.includes(k)).reduce((a, c) => (
    ...a,
    [c]: omit( obj[c], keys )
), ) : obj;

console.log( omit(x, ['key2']) );

console.log( omit(x, ['nested1']) );

console.log( omit(x, ['nested1','key1']) );

console.log( omit(x, ['key3']) );

【讨论】:

以上是关于JavaScript 从没有指定键的嵌套数组返回的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript:将具有父键的对象数组转换为父/子树(包括没有父的对象)

从没有参数的函数返回整数数组[重复]

如何计算数组中对象键的总和 - javascript

带有嵌套for循环的Javascript多维数组-无法正常工作

如何从没有数字主键的表中有效地选择随机行

从没有主键的临时表中删除重复字段 [重复]