【问题标题】:How do I preserve the order of this javascript array sort?如何保留此 javascript 数组排序的顺序?
【发布时间】:2021-05-08 20:11:56
【问题描述】:
const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
]

我正在尝试对数组进行排序,以便先出现 True 值,然后是 False 值。

const orderedModules = modules.sort((a, b) => (a.checked ? -1 : 1))

但是,我想保留 True 值的顺序。上面的代码有时会将 Air 放在首位,然后是 Earth(如果运行两次)。如何始终保持订单?

【问题讨论】:

    标签: javascript arrays algorithm object


    【解决方案1】:

    用作比较函数的回调可以返回 3 个选项:负数、正数或零。负数表示数组顺序中第一个参数应该在第二个参数之前。正数表示数组顺序中第一个参数应该在第二个参数之后。零表示订单应保持原样。

    Sort array method on MDN

    如果您想先在数组中以相同的顺序排列真值,然后是假值,如果两者都为真,则可能添加更多逻辑以从比较函数返回零将解决您的问题。

    这是一个例子:

    const modules = [
      { name: 'Wood', checked: false },
      { name: 'Metal', checked: false },
      { name: 'Earth', checked: true },
      { name: 'Water', checked: false },
      { name: 'Air', checked: true },
      { name: 'Fire', checked: false },
    ];
    modules.sort((a,b) => a.checked && b.checked ? 0 : a.checked ? -1 : 1);
    console.log(modules);
    
    【解决方案2】:

    如果您不介意创建一个新数组,只需对数组进行两次迭代即可。第一次,当迭代遇到具有真实值的对象时,将它们推送到新数组。第二次,推送具有错误值的对象。 (JavaScript 通过引用传递对象,因此新数组不会导致它们重复。)

    【讨论】:

      【解决方案3】:

      这可能会对您有所帮助。不确定优化方式,但此函数仅对数组进行一次迭代。

      我正在使用 reduce 函数来分离真假值,然后按您想要的顺序返回它们。

      const shortItems = (array) => {
          const orderedModulesObject = array.reduce((orderedModulesObject, currentModule) => {
                  if(currentModule.checked){
                      orderedModulesObject.trueValues = orderedModulesObject.trueValues.concat(currentModule);
                  } else {
                      orderedModulesObject.falseValues = orderedModulesObject.falseValues.concat(currentModule);
                  }
                  return orderedModulesObject;
              
          }, { trueValues: [], falseValues: []});
          return orderedModulesObject.trueValues.concat(orderedModulesObject.falseValues);
      }
      
      const modules = [
      { name: 'Wood', checked: false },
      { name: 'Metal', checked: false },
      { name: 'Earth', checked: true },
      { name: 'Water', checked: false },
      { name: 'Air', checked: true },
      { name: 'Fire', checked: false },
      ]
      
      console.log(shortItems(modules));

      【讨论】:

      【解决方案4】:

      原因是排序实际上改变了原始数组。虽然 modules 是用 const 定义的,但里面的值可以改变,只要你不把变量赋值给别的东西。

      根据这个answer,您可以使用扩展语法进行排序而不改变原始文件。这段代码应该可以工作:

      const orderedModules = [...modules].sort((a, b) => (a.checked ? -1 : 1))
      

      要使数组或对象无法修改,可以使用Object.freeze()

      const modules = Object.freeze([
          { name: 'Wood', checked: false },
          { name: 'Metal', checked: false },
          { name: 'Earth', checked: true },
          { name: 'Water', checked: false },
          { name: 'Air', checked: true },
          { name: 'Fire', checked: false },
      ])
      

      编辑:我刚刚意识到顺序不正确,但至少每次都是一样的。但那是因为排序不完全正确。这是正确的代码:

      const orderedModules = [...modules].sort((a, b) => (a.checked != b.checked ? (a.checked ? -1 : 1 ) : 0))
      

      【讨论】:

      • 我不认为 OP 关心改变原始数组中元素的顺序。我认为他们正在积极尝试改变它。他们希望在具有真实值的对象组内保持现有顺序。
      • 顺序改变的原因是因为原件在改变。 sort 不是随机的,但是当数组发生变化时,无论出于何种原因,sort 都会产生不同的输出
      猜你喜欢
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 2020-06-28
      • 2017-04-26
      • 1970-01-01
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      相关资源
      最近更新 更多