排序/操作对象数组

问题描述 投票:0回答:1

我需要帮助编写一个函数来对对象数组进行排序

  1. 所有带有
    xid
    的对象都位于数组的底部
  2. 具有选项数组的
  3. 对象(假设A)可能在步骤对象中包含
    xid
    ,这个xid也存在于根级别的其他对象中(假设B),在这种情况下B应该放在A下面

示例:

带有文本“寻找在线”的

对象具有

options
键,并且在第 0 个索引上,它具有带有
step
,
xid = "1"

对象
{
    type: 'radio',
    text: "Looking for online",
    options: [
       {
           text: "Yes",
           step: {
              text: "Select City",
              xid: 1
           }
        },
        {
            text: "No"
        }
    ]
}

现在根级别上

xid
= 1 的对象,即带有文本“选择城市”的对象应放置在第一个对象下方

{
    type: 'radio',
    text: "Looking for online",
    options: [
       {
           text: "Yes",
           step: {
              text: "Select City",
              xid: 1
           }
        },
        {
            text: "No"
        }
    ]
},
{
    type: 'radio',
    text: "Select City",
    xid: 1,
    options: [
        {
            text: "Mumbai",
            step: {
                text: "Select Area",
                xid: 2
            }
        },
        {
            text: "Delhi",
        }
    ]
}

同样,带有

text
="选择区域"的对象具有
xid
= 2,它应该放置在第 2 个

下方
{
    type: 'radio',
    text: "Looking for online",
    options: [
       {
           text: "Yes",
           step: {
              text: "Select City",
              xid: 1
           }
        },
        {
            text: "No"
        }
    ]
},
{
    type: 'radio',
    text: "Select City",
    xid: 1,
    options: [
        {
            text: "Mumbai",
            step: {
                text: "Select Area",
                xid: 2
            }
        },
        {
            text: "Delhi",
        }
    ]
},
{
    type: 'radio',
    text: "Select Area",
    xid: 2,
    options: [
        {
            text: "Yes",
        },
        {
            text: "No"
        }
    ]
}

输入:

let array = [
    {
        type: 'radio',
        text: "Looking for online",
        options: [
            {
                text: "Yes",
                step: {
                    text: "Select City",
                    xid: 1
                }
            },
            {
                text: "No"
            }
        ]
    },
    {
        type: "single",
        text: "First Name",
    },
    {
        type: "single",
        text: "Last Name"
    },
    {
        type: 'radio',
        text: "Select Area",
        xid: 2,
        options: [
            {
                text: "Yes",
            },
            {
                text: "No"
            }
        ]
    },
    {
        type: 'radio',
        text: "Select City",
        xid: 1,
        options: [
            {
                text: "Mumbai",
                step: {
                    text: "Select Area",
                    xid: 2
                }
            },
            {
                text: "Delhi",
            }
        ]
    },
]

预期输出:

let array = [
    {
        type: "single",
        text: "First Name",
    },
    {
        type: "single",
        text: "Last Name"
    },
    {
        type: 'radio',
        text: "Looking for online",
        options: [
            {
                text: "Yes",
                step: {
                    text: "Select City",
                    xid: 1
                }
            },
            {
                text: "No"
            }
        ]
    },
    {
        type: 'radio',
        text: "Select City",
        xid: 1,
        options: [
            {
                text: "Mumbai",
                step: {
                    text: "Select Area",
                    xid: 2
                }
            },
            {
                text: "Delhi",
            }
        ]
    },
    {
        type: 'radio',
        text: "Select Area",
        xid: 2,
        options: [
            {
                text: "Yes",
            },
            {
                text: "No"
            }
        ]
    },
];

我尝试编写一个快速 for 循环来操作对象索引,但在一次更新多个对象的位置时它会中断

const filteredArray = [...array];
for(let index = 0; index < filteredArray?.length; index++) {
  if (filteredArray[index]?.type === 'radio' && filteredArray[index].options && filteredArray[index]?.options?.length) {
    const length = (filteredArray[index].options && filteredArray[index]?.options?.length) || 0;
    for(let index1 = 0; index1 < length; index1++) {
      const option = filteredArray[index]?.options?.[index1];
      if (option && option?.step && option?.step?.xid){
        const idx = array.findIndex(item => item?.xid === option?.step?.xid);
        if (idx >= 0 && idx !== index + 1) {
          const removedItem = array.splice(idx, 1)[0];
          array.splice(index, 0, removedItem);
        } 
      }
    }
  }
}

提前抱歉,因为英语不是我的第一语言,我尝试在示例部分中解释尽可能多的内容

javascript arrays object ecmascript-6
1个回答
0
投票

这看起来像一个树结构,其中每个节点可能有一些选项/步骤。我将用它构建一棵树,其中孩子是相应的

[step]
。然后我将按照项目的出现顺序将其展平(深度优先搜索)。

可能还有其他你没有提供的排序要求(如果有几个“A”项?或悬空的“B”项怎么办),但这可以修改,树结构非常灵活。

函数

buildTree
flattenTree
几乎是不言自明的。

let arr = [{
    type: 'radio',
    text: "Looking for online",
    options: [{
        text: "Yes",
        step: {
          text: "Select City",
          xid: 1
        }
      },
      {
        text: "No"
      }
    ]
  },
  {
    type: "single",
    text: "First Name",
  },
  {
    type: "single",
    text: "Last Name"
  },
  {
    type: 'radio',
    text: "Select Area",
    xid: 2,
    options: [{
        text: "Yes",
      },
      {
        text: "No"
      }
    ]
  },
  {
    type: 'radio',
    text: "Select City",
    xid: 1,
    options: [{
        text: "Mumbai",
        step: {
          text: "Select Area",
          xid: 2
        }
      },
      {
        text: "Delhi",
      }
    ]
  },
]

function buildTree(items) {
  var result = []
  var lookup = {}

  // prepare lookup for fast access by xid
  items.forEach(item => lookup[item.xid] = item);

  // make all option.steps into array of children or []
  items.forEach(item => {
    var steps = (item.options || []).filter(item => item.step && item.step.xid).map(item => item.step.xid)
    item.children = steps.map(item => lookup[item])
  })

  // the roots of the tree are the items without xid (A items)
  items.forEach(item => {
    if (!item.xid) {
      result.push(item)
    }
  })

  // items without children should come first
  result.sort(function(a, b) {
    return a.children.length - b.children.length
  })

  return result
}

function flattenTree(tree) {
  const result = [];

  function dfs(node) {
    result.push(node);

    if (node.children) {
      node.children.forEach(child => dfs(child));
    }
  }

  tree.forEach(root => dfs(root));

  result.forEach (item => delete item.children)
  
  return result;
}


var tree = buildTree(arr)
var result = flattenTree(tree)

console.log(result)
.as-console-wrapper {
  min-height: 100%
}

© www.soinside.com 2019 - 2024. All rights reserved.