【问题标题】:How to iteratively nest objects within an object如何在对象中迭代地嵌套对象
【发布时间】:2022-11-15 08:25:50
【问题描述】:

我有一个看起来像这样的数组:

const arr = [
{
  parent: 'A',
  children: ['B'],
},
{
  parent: 'B',
  children: ['C'],
},
{
  parent: 'C',
  children: ['D']
}];

我想创建一个函数,它将接受这个数组并产生以下对象:

const result = {
  parent: 'A',
  children: [{
    parent: 'B',
    children: [{
      parent: 'C',
      children: [{
        parent: 'D',
        children: []
      }]
    }]
  }]
};

所以结果类型看起来像:

type Result = {
  parent: string;
  children: Result[];
};

到目前为止我已经尝试过:

type TInput = {
  parent: string;
  children: string[];
};

type Result = {
  parent: string;
  children: Result[];
};

// can assume we know initial parent is 'A'
const fn = (parent: string, inputArr: TInput[]) => {
  const result: TResult[] = [];

  let newParent: string[] = [];
  while (newParent.length !== 0) {
    const index = inputArr.findIndex(
      (input) => input.parent === parent
    );
    result.push({
      parent: inputArr[index].parent,
      children: [], // need to populate on next pass?
    });
    newParent = inputArr[index].children;
  }
  return result;
};

我不知道输入数组中有多少对象,但可以假设第一个对象已知是初始父/子(示例中为“A”)。非常感谢任何帮助。 谢谢

【问题讨论】:

  • 这个条件应该做什么? while (newParent.length !== 0) newParent 一开始总是一个空数组
  • 这回答了你的问题了吗? Build tree array from flat array in javascript
  • 此外,您的结果树属性命名与平面数据冲突。 parent: 'A' 应该表示该节点是 A 的子节点,但在您的树中,带有 parent: 'B' 的节点实际上是 A 的子节点
  • @PeterSeliger 我完全同意,这就是我在最初评论中所指的。它是可解的,但需要一个额外的循环来确定根节点(不是任何其他节点的子节点的节点)。
  • 在我看来,所选择的源代码结构已经存在缺陷。就父子关系和每个子父关系而言,它不是双射/双唯一的。当一个人试图阅读和弄清楚转换后的目标结构的目的时,它会变得很明显。这两种结构都远非直观。源结构应该是……const arr = [{ id: 'A', parentId: null }, { id: 'B', parentId: 'A' }, { id: 'C', parentId: 'B' }];……那么预期的结果就是……{ id: 'A', parentId: null, children: [{ id: 'B', parentId: 'A', children: [{ id: 'C', parentId: 'B' }] }] }

标签: javascript node.js arrays nested-object


【解决方案1】:

如果我说对了,您可以采用的一种方法是递归函数。在线阅读 cmets:

// Array
const arr = [
  {
    parent: 'A',
    children: ['B'],
  },
  {
    parent: 'B',
    children: ['C'],
  },
  {
    parent: 'C',
    children: ['D']
  }
];

// Alphabet
const alphabet = 'abcdefghijklmnopqrstuvwxyz'.toUpperCase().split('');

// Recursive function
const rf = (arr, i = 0) => {
  // Result object
  let result = [];
  // Loop through array of objects
  for(const obj of arr) {
    // If parent or children equals current letter
    if(obj.parent === alphabet[i] || obj.children[0] === alphabet[i]) {
      // Form object in array
      result = [{
        parent: alphabet[i],
        children: rf(arr, i+1) // Go recursive with letter+1
      }];
    }
  }
  // Return result
  return result;
}

// Test
console.log(rf(arr)[0]);

【讨论】:

    【解决方案2】:

    这似乎可以完成这项工作:

    这是ts 版本:

    // here i just copy your data
    const data = [{
        parent: 'A',
        children: ['B'],
      },
      {
        parent: 'C',
        children: ['D']
      },
      {
        parent: 'B',
        children: ['C'],
      }
    ];
    
    const expectedResult = {
      parent: 'A',
      children: [{
        parent: 'B',
        children: [{
          parent: 'C',
          children: [{
            parent: 'D',
            children: []
          }]
        }]
      }]
    };
    
    type TInput = {
      parent: string;
      children: string[];
    };
    
    type TResult = {
      parent: string;
      children: TResult[];
    };
    
    
    // there is the function that takes an input (the parent element) and an array (all the children)
    const parseArray = (obj: TInput, arr: TInput[]): TResult => {
      return {
        parent: obj.parent,
        // if the children exists on the array, we use it, else we create an empty one, which will be used to recusivly generate the tree
        children: obj.children.map(child => data.find(e => e.parent === child) ?? {
          parent: child,
          children: []
        }).map(e => parseArray(e, arr))
      }
    }
    
    // we get the root obj (as you said the first el)
    const root = data.shift()!
    
    // and we call the function
    console.log(parseArray(root, data))
    
    // we verify that the objects are the same using json (directly using == on objects compares their locations on the disk)
    console.log(JSON.stringify(parseArray(root, data)) === JSON.stringify(expectedResult))
    

    这是剪断的(我们不能直接在 sn-ps 上运行 ts):

    // here i just copy your data
    const data = [{
        parent: 'A',
        children: ['B'],
      },
      {
        parent: 'C',
        children: ['D']
      },
      {
        parent: 'B',
        children: ['C'],
      }
    ];
    
    const expectedResult = {
      parent: 'A',
      children: [{
        parent: 'B',
        children: [{
          parent: 'C',
          children: [{
            parent: 'D',
            children: []
          }]
        }]
      }]
    };
    
    // there is the function that takes an input (the parent element) and an array (all the children)
    const parseArray = (obj, arr) => {
      return {
        parent: obj.parent,
        // if the children exists on the array, we use it, else we create an empty one, which will be used to recusivly generate the tree
        children: obj.children.map(child => data.find(e => e.parent === child) ?? {
          parent: child,
          children: []
        }).map(e => parseArray(e, arr))
      }
    }
    
    // we get the root obj (as you said the first el)
    const root = data.shift()
    
    // and we call the function
    console.log(parseArray(root, data))
    
    // we verify that the objects are the same using json (directly using == on objects compares their locations on the disk)
    console.log(JSON.stringify(parseArray(root, data)) === JSON.stringify(expectedResult))

    【讨论】:

      猜你喜欢
      • 2016-05-30
      • 2021-05-19
      • 2013-07-01
      • 1970-01-01
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      相关资源
      最近更新 更多