【问题标题】:Javascript Array Sorting HeadacheJavascript数组排序头痛
【发布时间】:2014-06-09 00:47:38
【问题描述】:

我有一个与此类似的对象数组:

[
    {
        id : 1,
        position: false
    },
    {
        id: 2,
        position: false
    },
    {
        id: 3,
        position: 4
    },
    {
        id: 4,
        position: false
    },
    {
        id: 5,
        position: 2
    },
    {
        id: 6,
        position: 5
    },
    {
        id: 7,
        position: 3
    },
    {
        id: 8,
        position: 1
    },
]

我想使用每个对象的位置属性(升序)对这个数组进行排序,使数组看起来像这样:

[
    {
        id: 8,
        position: 1
    },
    {
        id: 5,
        position: 2
    },
    {
        id: 7,
        position: 3
    },
    {
        id: 3,
        position: 4
    },
    {
        id: 6,
        position: 5
    },
    {
        id: 1,
        position: false
    },
    {
        id: 2,
        position: false
    },
    {
        id: 4,
        position: false
    }
]

这个想法只是将位置不为假的对象移动到顶部,而不影响位置设置为假的其余对象的顺序。

看起来很简单,对吧?我试图以多种方式解决这个问题,但似乎没有任何方法能够可靠地工作。希望有人能帮助我弄清楚如何正确处理这个问题。

帮助我 Stack Overflow,你是我唯一的希望。

【问题讨论】:

  • 对象的语法无效。 = 应替换为冒号
  • 哇,我不敢相信我做到了。立即编辑。
  • 所以,我彻底修改了我原来的回复。希望对您有所帮助!

标签: javascript arrays sorting object


【解决方案1】:

我尝试添加一堆 cmets 来帮助您遵循我的想法。 这是以命令式风格实现的,并且(我希望)可以帮助说明如何处理类似问题的一些想法。

我使用了您的样本数据集,并重现了您正在寻找的结果。 我希望这会有所帮助,并且可以对其进行修改以适应您需要的任何数据。

I also pasted the text here.

var deepSort = function(arr){
  var i;
  var hasPositionKey = [];
  var noPositionKey = [];
  var nestedObj;
  var positions = [];
  var loggingPositions = {};
  var positionSortedObjects = [];

  // iterate through the array of objects
  for(i = 0; i < arr.length; i++){
    // set a variable for the individual object being considered
     nestedObj = arr[i];
    // if that object has a position of false
    if(nestedObj.position === false){
      // push false object into the array of false position objects
      noPositionKey.push(nestedObj);
    }
    // if the object has a numbered position
    if(typeof nestedObj.position === 'number'){
      // push numbered position to the array of numbered position objects
      hasPositionKey.push(nestedObj);
    }
  }

  // iterate through the array of objects with positions
  for(i = 0; i < hasPositionKey.length; i++){
    // set a variable for the individual object being considered
    nestedObj = hasPositionKey[i];
    // push only the position number into an array to track positions
    positions.push(nestedObj.position);
    // add a key value pair of position:id to an object
    loggingPositions[nestedObj.position] = nestedObj.id;
  }

  // sort the array that stores the positions of the non-false objects
  positions.sort();
  // iterate through that array and construct a final array of objects by sorted position
  for(i = 0; i < positions.length; i++){
    // set a variable for the positions, as encountered in order:
    var num = positions[i];
    // set a key for the object to be constructed
    var key = loggingPositions[num];
    // set a value for the object to be constructed
    var value = num;
    // construct a result object with object literal notation:
    var result = {
      id: key,
      position: value
    };
    // push the constructed objects into the positionSortedObjects array
    positionSortedObjects.push( result );
  }

  // return a concatenated array of the positionSortedObjects + the noPositionKey objects
  return (positionSortedObjects.concat(noPositionKey));  
};

var sample = [
    {
        id : 1,
        position: false
    },
    {
        id: 2,
        position: false
    },
    {
        id: 3,
        position: 4
    },
    {
        id: 4,
        position: false
    },
    {
        id: 5,
        position: 2
    },
    {
        id: 6,
        position: 5
    },
    {
        id: 7,
        position: 3
    },
    {
        id: 8,
        position: 1
    }
];

deepSort(sample);

【讨论】:

  • 您好,如果您发现任何一个有用的答案,请选择一个作为官方答案。建立声誉对这个网站有很大帮助。谢谢!
【解决方案2】:

对数据进行排序的简单方法是使用Array.sort() 函数。首先检查对象 2 的位置是否为假,如果是则返回 -1 以将对象 1 浮动到顶部。对对象 1 执行相反的操作。如果两者都不为假,则进行整数比较。

var data = [
    { id: 1, position: false },
    { id: 2, position: false }, 
    { id: 3, position: 4 },
    { id: 4, position: false },
    { id: 5, position: 2 },
    { id: 6, position: 5 },
    { id: 7, position: 3 },
    { id: 8, position: 1 }
];

data.sort(function (a, b) {
    posa = a.position;
    posb = b.position;
    
    if (!posb) return -1;
    if (!posa) return 1;
    
    return posa - posb;
});

console.log(data);

但是这个解决方案可能不是最好的,因为Array.sort() 不需要根据 ECMA International 的标准:

以下摘自ECMAScript Language Specification, 2011, p.129

15.4.4.11 Array.prototype.sort(比较)

此数组的元素已排序。排序不一定是稳定的(也就是说,比较相等的元素不一定保持原来的顺序)。如果 comparefn 不是未定义的,它应该是一个接受两个参数 x 和 y 的函数,如果 x y 返回正值。

解决此问题的方法是让您设计自己的排序算法。最好是合并或快速排序算法。下面是用于按预期对数据进行排序的快速排序算法的实现。 注意:此响应底部有一个指向 JSFiddle 的链接。

/**
 *  Add a swap function to the Array object.
 *  @param a Object a.
 *  @param b Object b.
 */
Array.prototype.swap = function (a, b) {
    var tmp = this[a];
    this[a] = this[b];
    this[b] = tmp;
};

/**
 *  A utility function to print out HTML to the screen in case the user's
 *  console is not enabled or present.
 *  @param message The message to print to the screen.
 */
var trace = function (message) {
    id = 'trace';
    t = $('#' + id);
    if (t.length < 1) t = $('<div>', {
        'id': id
    }).appendTo($('body'));
    t.append($('<p>', {
        'html': message
    }));
};

/**
 *  An implementation of the quick-sort algorithm that allows the user to
 *  use a custom comparator with the following signature
 *  {@code function(a, b) } which will return an integer value to determine
 *  ordering. 
 *  @param array The array to be sorted.
 *  @param comparator The custom comparator function.
 */
var quickSort = function (array, comparator) {
    var __internal_compare__ = function compare(a, b) {
        if (a < b) return -1;
        if (a > b) return 1;
        return 0;
    };
    
    comparator = comparator || __internal_compare__;
    
    var qsort = function (array, begin, end, comparator) {
        if (end - 1 > begin) {
            var pivot = begin + Math.floor(Math.random() * (end - begin));

            pivot = partition(array, begin, end, pivot, comparator);

            qsort(array, begin, pivot, comparator);
            qsort(array, pivot + 1, end, comparator);
        }
    };

    var partition = function (array, begin, end, pivot, comparator) {
        var piv = array[pivot];
        array.swap(pivot, end - 1);
        var store = begin;
        var ix;
        
        for (ix = begin; ix < end - 1; ++ix) {
            if (piv != undefined && comparator(piv, array[ix]) < 0) {
                array.swap(store, ix);
                ++store;
            }
        }
        
        array.swap(end - 1, store);

        return store;
    };

    qsort(array, 0, array.length, comparator);
};

// The custom compare function to be used on the array of data below
// in the quick-sort function.
var compare = function (a, b) {
    var isBoolAndFalse = function (val) {
        return typeof val === 'boolean' && !val;
    };

    if (a == b) return 0;

    var posa = a.position;
    var posb = b.position;
    var cona = isBoolAndFalse(posb);
    var conb = isBoolAndFalse(posa);

    if (cona && conb) {
        var ida = a.id;
        var idb = b.id;

        return idb - ida;
    }

    if (conb) return -1;
    if (cona) return 1;

    return posb - posa;
};

/**
 *  Main procedure follows:
 */

var data = [
    { id: 1, position: false },
    { id: 2, position: false }, 
    { id: 3, position: 4 },
    { id: 4, position: false },
    { id: 5, position: 2 },
    { id: 6, position: 5 },
    { id: 7, position: 3 },
    { id: 8, position: 1 }
];

quickSort(data, compare);

trace(JSON.stringify(data, undefined, 2));

输出:

[
  {
    "id": 8,
    "position": 1
  },
  {
    "id": 5,
    "position": 2
  },
  {
    "id": 7,
    "position": 3
  },
  {
    "id": 3,
    "position": 4
  },
  {
    "id": 6,
    "position": 5
  },
  {
    "id": 1,
    "position": false
  },
  {
    "id": 2,
    "position": false
  },
  {
    "id": 4,
    "position": false
  }
]

您可以使用以下 JSFiddle Demo 测试上述代码。我希望这能为您解决问题。

【讨论】:

  • .sort 在 javascript 中不稳定,因此它不符合“不影响位置设置为 false 的其余对象的顺序”要求(在您当前的实现中)
  • 使用 underscore.js 的 _.sortBy() 会更稳定吗?
  • 而且,以防万一:posa=0 也将被认为是错误的(如果发生这种情况),现在检查的方式 (!posa)(等 b)。不过,OP 应该重新考虑文字的设计,也许有一个与位置不同的标志。
  • @Franky Chanyau:根据文档 - underscore.js 的.sortBy() 是一个稳定的实现。 PS:您不会说“更稳定” - 实现是否稳定:-) 请参阅en.wikipedia.org/wiki/Sorting_algorithm#Stability 以获取参考
  • @Epistemex 我解决了false 的问题,方法是检查其类型然后检查其值。
猜你喜欢
  • 2010-12-14
  • 2012-07-29
  • 1970-01-01
  • 2010-12-02
  • 2017-03-27
  • 2017-10-26
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
相关资源
最近更新 更多