【问题标题】:Sort multidimensional array of objects with a variable depth in Javascript在Javascript中对具有可变深度的对象的多维数组进行排序
【发布时间】:2016-01-14 09:16:57
【问题描述】:

所以我最近遇到了一个我似乎无法解决的问题。

假设我在 javascript 中定义了一个对象数组,并希望用户能够选择对该数组进行排序的值。 当我知道深度时,我对数组进行排序没有问题,因为它类似于

array = array.sort(function (a, b) {
    return b["foo"]["bar"] - a["foo"]["bar"];
});

但是当深度未知时,我不完全知道如何去做。我尝试将键放在一个字符串中并使用 eval(),但这似乎不起作用。

我在 JSFiddle 上设置了一个快速示例,以更好地说明我的意思 http://jsfiddle.net/DakotaSv/c35bj02w/2/

如果有人能想到解决方案,我将不胜感激!

(感谢 PatrickD,here is the working JSFiddle,感谢任何可能觉得它有用的人!)

【问题讨论】:

  • 您可能正在寻找某种“对象中的递归搜索” 来查找键?
  • 最好是创建一个对象结构来处理这种复杂性,而不仅仅是一个单行。

标签: javascript jquery arrays sorting multidimensional-array


【解决方案1】:

你需要:

  1. 一种表示如何访问给定对象的排序键的方法
  2. 一个函数,给定一个排序键表示和一个对象,查询该对象并生成键

表示方式可以任意选择,假设我们决定将访问someObject.foo.bar编码为字符串"foo.bar"。那么关键生成函数将是(改编自我的回答here):

function produceKey(target, path) {
    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (typeof target[branch] === 'undefined') {
            return undefined;
        }

        target = target[branch];
    }

    return target;
}

然后您可以将其用作:

function produceKey(target, path) {
  var parts = path.split('.');

  while(parts.length) {
    var branch = parts.shift();
    if (typeof target[branch] === 'undefined') {
      return undefined;
    }

    target = target[branch];
  }

  return target;
}

var obj = { foo: { bar: 1, baz: 2 }, arr: [1, 2, 3] };

$(function() {
  $("#trigger").click(function() {
    $(".result").text(JSON.stringify(produceKey(obj, $("input").val())));
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Targe object: 
<pre>
{ foo: { bar: 1, baz: 2 }, arr: [1, 2, 3] } 
</pre>


Property path: <input name="path" />
<button id="trigger">Produce value</button>
<div class="result"></div>

【讨论】:

    【解决方案2】:

    如果我正确理解您的问题,您希望用户选择对数组进行排序的属性。 看着你的小提琴,我认为你需要的是访问用户指定的属性,幸运的是可以在括号内指定一个变量。比如:

    var obj = {name: 'john'}
    var attr = "name";
    console.log(obj[attr]); // prints 'john'
    

    这是你修改后的小提琴:https://jsfiddle.net/9s5bnfh5/1/

    【讨论】:

      【解决方案3】:

      这是一个可行的解决方案。它使用 ES6 语法,但这应该不是问题:

      'use strict'
      
      var users = [
        {'Name' : 'John', 'Attributes' : {'Age' : 5, 'Height' : 1.5, 'Clothes' : {'Shirts' : 5, 'Pants' : 8}}}, 
        {'Name' : 'Andrew', 'Attributes' : {'Age' : 9, 'Height' : 1.8, 'Clothes' : {'Shirts' : 2, 'Pants' : 5}}}, 
        {'Name' : 'Lucifer', 'Attributes' : {'Age' : 11, 'Height' : 1.3, 'Clothes' : {'Shirts' : 9, 'Pants' : 4}}}
      ];
      
      function sort(valuePath, array){
        let path = valuePath.split('.')  
      
        return array.sort((a, b) => {
           return getValue(b,path) -  getValue(a,path)    
        });
      
        function getValue(obj, path){
          path.forEach(path => obj = obj[path])
          return obj;
        }
      }
      
      
      console.log(sort('Attributes.Height', users))
      console.log(sort('Attributes.Clothes.Shirts', users))
      

      输出是正确的。

      【讨论】:

        【解决方案4】:

        也许这是变量排序方案的解决方案。刚刚给出了 sort 属性,例如 ['Attributes', 'Height']。这使用属性AttributesHeight

        它具有临时存储空间,可加快分类速度。

        function sort(a, by) {
            return a.map(function (el, i) {
                return {
                    index: i,
                    value: by.reduce(function (obj, property) { return obj[property]; }, el)
                };
            }).sort(function (a, b) {
                return a.value - b.value;
            }).map(function (el) {
                return a[el.index];
            });
        }
        var users = [{ 'Name': 'John', 'Attributes': { 'Age': 5, 'Height': 1.5, 'Clothes': { 'Shirts': 5, 'Pants': 8 } } }, { 'Name': 'Andrew', 'Attributes': { 'Age': 9, 'Height': 1.8, 'Clothes': { 'Shirts': 2, 'Pants': 5 } } }, { 'Name': 'Lucifer', 'Attributes': { 'Age': 11, 'Height': 1.3, 'Clothes': { 'Shirts': 9, 'Pants': 4 } } }];
        document.write('<pre>' + JSON.stringify(sort(users, ['Attributes', 'Height']), 0, 4) + '</pre>');
        document.write('<pre>' + JSON.stringify(sort(users, ['Attributes', 'Clothes', 'Shirts']), 0, 4) + '</pre>');

        【讨论】:

          【解决方案5】:

          执行此操作的最简洁方法是将回调函数传递给排序算法,执行该函数以从对象中检索要比较的值:

          function cbSort(toSort, callback)
          {
              return toSort.sort(function(a, b) 
              {
                  return callback(a) - callback(b);
              }
          }
          
          // usage
          var data = [ { x: 1, y: 2 }, {x: 3, y: 1}];
          var sorted = cbSort(data, function(item) {
              return item.x; // make this as complex as you like
          });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-15
            • 2015-07-11
            • 2015-01-29
            • 2017-11-09
            • 1970-01-01
            • 2011-10-23
            • 2020-03-20
            相关资源
            最近更新 更多