【问题标题】:Javascript Recursion thru children and display in HTMLJavascript通过子级递归并以HTML显示
【发布时间】:2020-08-03 18:48:22
【问题描述】:

我想根据嵌套子项的值显示结果。我为此使用递归函数。根据下面的示例结果,我无法将其显示为 HTML。 我正在使用 React.js。

现在我正在使用 console.log。 这是我的代码:(示例数据在底部)

function recursion(data, label) {
  if (!data) {
    return;
  }
  for (let a = 0; a < data.length; a++) {
    const item = data[a]
    if (!item.items) {
      const isLast = data.length - a === a
      console.log(`(${item.course_id}) ${ isLast ? '' : label} `)
    } else {
      if (label) console.log(label)
      recursion(item.items, item.type)
    }
  }
}

/*
Example result that I want to achieve is something like be: 

    (1894 $or 1501)
    $or
    (7068 $or 7120 or 7141) 
    $or 
	(997 $and 9001)
    $or
    (7256 $or 4534)
*/

//My sample data:

const data = [{
  "type": "$or",
  "items": [{
      "course_id": "1894"
    },
    {
      "course_id": "1501"
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7068"
        },
        {
          "course_id": "7120"
        },
        {
          "course_id": "7141"
        },
        {
          "type": "$and",
          "items": [{
              "course_id": "997"
            },
            {
              "course_id": "9001"
            }
          ]
        }
      ]
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7256"
        },
        {
          "course_id": "4534"
        }
      ]
    }
  ]
}]

//start here
recursion(data)

【问题讨论】:

  • 按console.log显示?
  • 不,我想在 HTML 中将其显示为文本。我只是使用 console.log 进行调试。
  • 997前面应该有缩进还是故意的?
  • 不需要缩进。我会编辑它。
  • 我更新了我的代码,我几乎得到了它,但现在,我在 console.log 中显示它,我的结果中仍然存在一个小问题。 @科林

标签: javascript html css reactjs ecmascript-6


【解决方案1】:

将项目中的所有叶节点(没有子节点的节点)放入一个数组中,然后递归到节点中。然后使用 $type 将它们连接在一起。

const data = [{
  "type": "$or",
  "items": [
    {
      "course_id": "1894"
    },
    {
      "course_id": "1501"
    },
    {
      "type": "$or",
      "items": [
        {
          "course_id": "7068"
        },
        {
          "course_id": "7120"
        },
        {
          "course_id": "7141"
        },
        {
          "type": "$and",
          "items": [
            {
              "course_id": "997"
            },
            {
              "course_id": "9001"
            }
          ]
        }
      ]
    },
    {
      "type": "$or",
      "items": [
        {
          "course_id": "7256"
        },
        {
          "course_id": "4534"
        }
      ]
    }
  ]
}]

/*
function recursion(data, label) {
  if (!data) { return; }
  for (let a = 0; a < data.length; a++) {
    const item = data[a]
    if (!item.items){
      console.log(`${item.course_id} ${label} `)
    } else {
      console.log('')
      console.log(label || '')
      setParentLabel = item.type
      const child = recursion(item.items, setParentLabel)
    }
  }
}
*/
const recursion = (data, label) => {
  let nodes = [[]];
  const type = data.type;
  data.items.forEach( x => {
    const leafs = nodes[0];
    const isLeaf = !x.items;
    if ( isLeaf ) leafs.push( x.course_id );
    else nodes.push( recursion( x, x.type ) );
  });
  if ( nodes[0].length > 0 )
    nodes[0] = '('+nodes[0].join(` ${type} `)+')';
  else nodes = nodes.slice(1);
  let string = '';
  string = nodes.join(`\n${type}\n`);
  return string;
};
console.log(recursion({items: data}))

const data = [{
  "type": "$or",
  "items": [
    {
      "course_id": "1894"
    },
    {
      "course_id": "1501"
    },
    {
      "type": "$or",
      "items": [
        {
          "course_id": "7068"
        },
        {
          "course_id": "7120"
        },
        {
          "course_id": "7141"
        },
        {
          "type": "$and",
          "items": [
            {
              "course_id": "997"
            },
            {
              "course_id": "9001"
            }
          ]
        }
      ]
    },
    {
      "type": "$or",
      "items": [
        {
          "course_id": "7256"
        },
        {
          "course_id": "4534"
        }
      ]
    }
  ]
}]

/*
Example result that I want to achieve is something like be: 

    (1894 $or 1501)
    $or
    (7068 $or 7120 or 7141) 
    $or 
	(997 $and 9001)
    $or
    (7256 $or 4534)
*/

function recursion(data, label) {
  if (!data) { return; }
  let nodes = [[]];
  let leafs = nodes[0];
  for (let a = 0; a < data.length; a++) {
    const item = data[a]
    if (!item.items){
      leafs.push(item.course_id)
    } else {
      setParentLabel = item.type
      const child = recursion(item.items, setParentLabel)
      nodes.push(child);
    }
  }
  if ( nodes[0].length > 0 )
    nodes[0] = '(' + nodes[0].join(` ${label} `) + ')';
  else nodes = nodes.slice(1);
  return nodes.filter(x=>!!x).join(`\n${label}\n`);
}

console.log(recursion(data))

【讨论】:

  • 我也可以将其显示为 HTML 吗?我正在使用 React.js。
  • 当然,我将发布一个更直接基于您的版本。基本上,您可以返回 React 组件,而不是返回字符串,并让 React 组件自行创建。
  • 看起来像return &lt;&gt; { nodes.filter(x=&gt;!!x).map(x=&gt;&lt;RecursiveComponent items={x.items} label={x.type}&gt;&lt;/RecursiveComponent&gt;) &lt;&gt;
  • 我建议您自己动手并弄清楚,因为您似乎正在学习 React。将是一个很好的练习练习,可以对 React 的结构有一个基本的感觉
  • 也许为叶节点、子节点和节点列表创建单独的组件,只是为了感受一下组件,尽管这并不是真正必要的。只是我的两分钱。
【解决方案2】:

const unSortedData = [{
  "type": "$or",
  "items": [{
      "course_id": "1894"
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7068"
        },
        {
          "course_id": "7120"
        },
        {
          "course_id": "7141"
        },
        {
          "type": "$and",
          "items": [{
              "course_id": "997"
            },
            {
              "course_id": "9001"
            }
          ]
        }
      ]
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7256"
        },
        {
          "course_id": "4534"
        }
      ]
    },
    {
      "course_id": "1501"
    }
  ]
},
{
  "type": "$or",
  "items": [{
      "course_id": "1894"
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7068"
        },
        {
          "course_id": "7120"
        },
        {
          "course_id": "7141"
        },
        {
          "type": "$and",
          "items": [{
              "course_id": "997"
            },
            {
              "course_id": "9001"
            }
          ]
        }
      ]
    },
    {
      "type": "$or",
      "items": [{
          "course_id": "7256"
        },
        {
          "course_id": "4534"
        }
      ]
    },
    {
      "course_id": "1501"
    }
  ]
}]
 /**Inorder to split between two data I have used value.type if you want
    *something else then you can use your own delimiter(just replace 
    *value.type with your requirement). Also if you want to store the looped 
    *item, you can store it into an array rather than returning string value. 
    *Example instead of dataJoiner you an use
    *const arr = [];
    *Inside forEach loop. arr.push(loopItems(value.items, value.type));
    *and finally return arr. It's clearly upto you what you want to do with 
    *the recursed item
**/
function loopData(data) {
	let dataJoiner = '';
	data.forEach(value => {
		dataJoiner = `${dataJoiner}\n ${dataJoiner ? ' ' + value.type + ' '  : dataJoiner}\n ${loopItems(value.items, value.type)})`;			
	});	
  console.log(dataJoiner);
  return dataJoiner;
};

 /** In this method items are sorted as per object type. Objects with only 
    *course_id are sorted and then Object with items are sorted. After that 
    *using     
    *reduce funtion it checks whether item has type and if it hasn't it     
    *accumulates by joining course_id with the given type. And whenever it     
    *detects type on the item it recursively calls loopItems whose result is     
    *accumulated into accumulator i.e. acc
**/
function loopItems(items, type) {
	if(items && items.length) {
	const sortedItems = items.sort((a, b) => Object.keys(a).length - Object.keys(b).length);
		return sortedItems.reduce((acc, item, index) => {
			if(item.type) {
			    return `${acc})\n ${acc ? ' ' + type + ' '  : acc}\n ${loopItems(item.items, item.type)}`;	
			}
			const leftBracket = index === 0 ? '(' : '' 
			return `${leftBracket }${acc}${acc ? ' ' + type + ' '  : acc}${item.course_id}`;
		}, '');
	}
}

loopData(unSortedData);

【讨论】:

    【解决方案3】:
    function recursion(items, type = '') {
        let result = [];
        for (let item of items) {
            if (!item.items && !item.type) {
                result.push(item.course_id);
            } else {
                result.push(`(${recursion(item.items, item.type)})`);
            }
        }
        return result.join(` ${type} `);
    }
    
    //start here
    console.log(recursion(data));
    

    【讨论】:

    • 感谢您的回答,我试过了,但是有一些小问题,例如关闭每个项目的括号。
    猜你喜欢
    • 2020-09-07
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多