【问题标题】:Sort array of objects of objects in javascript在javascript中对对象的对象数组进行排序
【发布时间】:2019-01-08 00:06:02
【问题描述】:

我想按“用户”对象中的“名称”对下面的数组进行排序

 var myArr = [
 {"id":1,"user":{"name":"allen","id":101}},
 {"id":2,"user":{"name":"martin","id":102}}
]

我该怎么做?

我有一种方法可以对对象数组进行排序,但我不能将它用于对象数组

这是方法:

function dynamicSort(property) {
    var sortOrder = 1;
    if (property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a, b) {
            var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

然后我可以使用这个排序:

myArr.sort(dynamicSort("id"));

【问题讨论】:

标签: javascript arrays sorting javascript-objects


【解决方案1】:

我会将属性创建为 getter 函数(对于复杂的示例。您可以检查 propFn 是否是一个函数,对于更复杂的例子,请在下面使用它。请参阅 this answer 以检查 propFn 是一个函数。) :

var myArr = [
  {"id":1,"user":{"name":"allen","id":101}},
  {"id":2,"user":{"name":"martin","id":102}}
]

function dynamicSort(propFn, sortOrder = 1) {
    return function (a, b) {
        var result = (propFn(a) < propFn(b)) ? -1 : (propFn(a) > propFn(b)) ? 1 : 0;
        return result * sortOrder;
    }
}

console.log(myArr.sort(dynamicSort((obj) => obj.user.name)));
console.log(myArr.sort(dynamicSort((obj) => obj.user.name, -1)));

或者,您可以查看:Convert JavaScript string in dot notation into an object reference

这将使您了解如何将句点符号转换为嵌套对象,但我建议您阅读顶部的免责声明。

为了保持向后兼容性,您可以使用如下所示的内容:

var myArr = [
  {"id":1,"user":{"name":"allen","id":101}},
  {"id":2,"user":{"name":"martin","id":102}}
]

function dynamicSort(propFn, sortOrder = 1) {
    if (typeof propFn === "string") {
        let prop = propFn;
        if (prop[0] === "-") {
            sortOrder = -1;
            prop = prop.substr(1);
        }

        propFn = (obj) => obj[prop];
    }
    return function (a, b) {
        var result = (propFn(a) < propFn(b)) ? -1 : (propFn(a) > propFn(b)) ? 1 : 0;
        return result * sortOrder;
    }
}

console.log(myArr.sort(dynamicSort((obj) => obj.user.name)));
console.log(myArr.sort(dynamicSort((obj) => obj.user.name, -1)));
console.log(myArr.sort(dynamicSort("id")));
console.log(myArr.sort(dynamicSort("-id")));

【讨论】:

  • 真的很好看,只是路过,但我一定会用的,谢谢!
【解决方案2】:

试试这个。适合我

var sortedArray = myArr.sort((a, b) => {

        const
            nameA = a.user.name.toUpperCase(),
            nameB = b.user.name.toUpperCase();

        if(nameA < nameB)
            return -1;

        if(nameA > nameB)
            return 1;

        return 0;
    });

【讨论】:

  • 这不是真正的动态,这(虽然不是很清楚)是 OP 的问题
  • 我认为评论清楚地表明了这个答案有什么问题。同样,OP 实际上是在寻求一种解决方案,他们可以使用不同的或动态的键进行排序。如果还不清楚,你可能想看看我的答案
【解决方案3】:

您可以使用sort 方法,但您首先需要获取嵌套属性,为此您可以传递一个字符串,然后使用reduce 方法获取属性。

 var myArr = [{"id":2,"user":{"name":"martin","id":102}}, {"id":1,"user":{"name":"allen","id":101}}]

function dynamicSort(arr, prop) {
  function getVal(obj, prop) {
    return prop.split('.').reduce((r, e) => r[e] || {}, obj)
  }

  arr.sort((a, b) => {
    let vA = getVal(a, prop);
    let vB = getVal(b, prop);
    return vA.localeCompare(vB)
  })
}

dynamicSort(myArr, "user.name")
console.log(myArr)

【讨论】:

    【解决方案4】:
    myArr.sort(function(a, b) {
        return a.user.name.localeCompare(b.user.name);
    });
    

    【讨论】:

    • 这不是真正的动态,这(虽然不是很清楚)是 OP 的问题
    • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation would greatly improve its long-term value 通过展示为什么这是一个很好的解决问题的方法,并将使其对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
    【解决方案5】:

    编辑:

    如果您因为键名中的句点而遇到问题,这种方法可能更适合作为解决方案。路径必须以括号符号访问器或点开头:

    function dynamicSort(property, order) {
      order||(order=1);
      const getter = new Function("obj", "return obj" + property + ";");
      return function(a, b) {
        var result = (getter(a) < getter(b)) ? -1 : (getter(a) > getter(b)) ? 1 : 0;
        return result * order;
      }
    }
    
    var myArr = [{
        "id": 1,
        "user": {
          "name": "allen",
          "id": 101
        }
      },
      {
        "id": 2,
        "user": {
          "name": "martin",
          "id": 102
        }
      },
      {
        "id": 3,
        "user": {
          "name": "barry",
          "id": 103
        }
      }
    ]
    
    console.log(JSON.stringify(myArr.sort(dynamicSort(".user.name"))));

    使用this answer 中的Object.byString() 方法,您可以重写您的函数以获取要排序的属性的路径:

    var myArr = [
     {"id":1,"user":{"name":"allen","id":101}},
     {"id":2,"user":{"name":"martin","id":102}},
     {"id":3,"user":{"name":"barry","id":103}}
    ]
    
    console.log(JSON.stringify(myArr.sort(dynamicSort("user.name"))));
    
    
    function dynamicSort(property) {
        var sortOrder = 1;
        if (property[0] === "-") {
            sortOrder = -1;
            property = property.substr(1);
        }
        return function (a, b) {
                var result = (byString(a, property) < byString(b, property)) ? -1 : (byString(a, property) > byString(b, property)) ? 1 : 0;
            return result * sortOrder;
        }
    }
    
    function byString(o, s) {
        s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
        s = s.replace(/^\./, '');           // strip a leading dot
        var a = s.split('.');
        for (var i = 0, n = a.length; i < n; ++i) {
            var k = a[i];
            if (k in o) {
                o = o[k];
            } else {
                return;
            }
        }
        return o;
    }

    我认为如果您将订单作为第二个参数,它会更清晰和更容易使用,这意味着您的函数应该或多或少看起来像这样:

    function dynamicSort(property, order) {
      return function(a, b) {
        var result = (byString(a, property) < byString(b, property)) ? -1 : (byString(a, property) > byString(b, property)) ? 1 : 0;
        return result * order;
      }
    }

    【讨论】:

    • 不错!起初这似乎很有挑战性,但最终找到解决方案并不难:-)
    • 如果键中实际上包含句点怎么办?我一直反对这样的解决方案,因为它们往往会带来比它们价值更多的麻烦。 (阅读this answer 顶部的巨大免责声明,这是byString 方法的另一种替代方法。)
    • 是的,我并没有真正考虑到这一点,免责声明非常正确,可能值得@kouroshstst 阅读。
    • 您的编辑本质上是 EVAL,而且情况要糟糕得多。如果没有正确清理,它会打开您的应用程序以应对可能是一些讨厌的 XSS 攻击。
    • @FrankerZ xss 攻击是什么意思?提供给此方法的数组来自 redux 存储,而 redux 存储由来自 api 的请求填充
    【解决方案6】:

    查看this SO answer 以获得基本相似问题的答案。

    由于该答案中的函数的调用方式与您的不同,将要排序的数组作为参数传入,您可以将其重构为以与现有 dynamicSort 函数相同的方式调用,如下所示:

    function dynamicSort(property) {
        var sortOrder = 1;
        if (property[0] === "-") {
            sortOrder = -1;
            property = property.substr(1);
        }
        var prop = property.split('.');
        var len = prop.length;
    
        return function (a, b) {
            var i = 0;
            while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
            var result = (a < b) ? -1 : (a > b) ? 1 : 0;
            return result * sortOrder;
        }
    }
    

    你可以这样称呼它:myArr.sort(this.dynamicSort("user.name"))

    这是一个可以工作的 sn-p 来演示:

    function dynamicSort(property) {
        var sortOrder = 1;
        if (property[0] === "-") {
            sortOrder = -1;
            property = property.substr(1);
        }
    	var prop = property.split('.');
        var len = prop.length;
    
        return function (a, b) {
    		var i = 0;
            while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
            var result = (a < b) ? -1 : (a > b) ? 1 : 0;
            return result * sortOrder;
        }
    }
    
    var myArr = [
    	{"id":1,"user":{"name":"allen","id":101}},
    	{"id":2,"user":{"name":"martin","id":102}},
    	{"id":3,"user":{"name":"beth","id":103}},
    ];
    
    console.log(myArr.sort(this.dynamicSort("user.name"))); //expected output: [{id:1, user:{name:"allen",...}}, {id:3, user:{name:"beth",...}}, {id:2, user:{name:"martin",...}}]

    【讨论】:

    • 我在上面的好答案被贡献之前就开始了这个答案,但被打断了。现在我只想完成并贡献它,以防万一调用它的可能更简单的语法对任何查看这个问题的人有吸引力。
    猜你喜欢
    • 2018-03-18
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 2022-06-17
    • 2018-08-18
    • 1970-01-01
    • 2011-09-06
    相关资源
    最近更新 更多