按键值对数组进行排序

20

我有一个目前按名称排序的函数和一个值/键对数组。

我想知道如何传递用于排序的键,以便每次可以调用相同的函数,就像这样:

var arr = [{name:'bob', artist:'rudy'},
           {name:'johhny', artist:'drusko'},
           {name:'tiff', artist:'needell'},
           {name:'top', artist:'gear'}];

sort(arr, 'name');   //trying to sort by name
sort(arr, 'artist'); //trying to sort by artist

function sort(arr) {
  arr.sort(function(a, b) {
    var nameA=a.name.toLowerCase(), nameB=b.name.toLowerCase();
    if (nameA < nameB) //sort string ascending
      return -1;
    if (nameA > nameB)
      return 1;
    return 0; //default return value (no sorting)
   });          
}

添加语言标签 - Arun Killu
JavaScript,看起来是这样。 - Maxim Kumpan
这是一个重复的问题,链接如下:https://dev59.com/Zm035IYBdhLWcg3wbPjc - Xavier
5个回答

46
Array.prototype.sortOn = function(key){
    this.sort(function(a, b){
        if(a[key] < b[key]){
            return -1;
        }else if(a[key] > b[key]){
            return 1;
        }
        return 0;
    });
}



var arr = [{name:'bob', artist:'rudy'},{name:'johhny', artist:'drusko'},{name:'tiff', artist:'needell'},{name:'top', artist:'gear'}];

arr.sortOn("name");
arr.sortOn("artist");

2
比上面更加优雅的解决方案! - Megan Caithlyn
1
同意。这是更优雅、更简单的方案。应该标记为正确答案。干得好! - Anthony Hessler
1
我知道这很老,但请注意,由于大写字母的ASCII值比小写字母小(至少我认为是这样),所以此算法将在“宇航员”之前对“独角兽”进行排序。 - Newclique
这是正确的答案。来自kooilnic的那个根本不起作用,要小心!! - Giox

20

[2020/08/14修订] 这是一个相当陈旧的答案,也不是很好,因此进行了简化和修订。

创建一个函数,返回排序lambda(实际排序所使用的Array.prototype.sort回调函数)。该函数可以接收键名、排序类型(区分大小写或不区分大小写的字符串或数字)和排序顺序(升序/降序)。Lambda使用参数值(闭包)来确定如何进行排序。

const log = (...strs) => 
  document.querySelector("pre").textContent += `\n${strs.join("\n")}`;
const showSortedValues = (arr, key) => 
  ` => ${arr.reduce((acc, val) => ([...acc, val[key]]), [])}`;
  
// the actual sort lamda factory function
const sortOnKey = (key, string, desc) => {
  const caseInsensitive = string && string === "CI";
  return (a, b) => {
    a = caseInsensitive ? a[key].toLowerCase() : a[key];
    b = caseInsensitive ? b[key].toLowerCase() : b[key];
    if (string) {
      return desc ? b.localeCompare(a) : a.localeCompare(b);
    }
    return desc ? b - a : a - b;
  }
};

// a few examples
const onNameStringAscendingCaseSensitive = 
  getTestArray().sort( sortOnKey("name", true) );
const onNameStringAscendingCaseInsensitive = 
  getTestArray().sort( sortOnKey("name", "CI", true) );
const onValueNumericDescending = 
  getTestArray().sort( sortOnKey("value", false, true) );

// examples
log(`*key = name, string ascending case sensitive`,
  showSortedValues(onNameStringAscendingCaseSensitive, "name")
);

log(`\n*key = name, string descending case insensitive`,
  showSortedValues(onNameStringAscendingCaseInsensitive, "name")
);

log(`\n*key = value, numeric desc`, 
  showSortedValues(onValueNumericDescending, "value")
);

function getTestArray() {
  return [{
    name: 'Bob',
    artist: 'Rudy',
    value: 23,
  }, {
    name: 'John',
    artist: 'Drusko',
    value: 123,
  }, {
    name: 'Tiff',
    artist: 'Needell',
    value: 1123,
  }, {
    name: 'Top',
    artist: 'Gear',
    value: 11123,
  }, {
    name: 'john',
    artist: 'Johanson',
    value: 12,
  }, ];
}
<pre></pre>


我的错误,你最初的答案实际上适用于数字排序(我只是有字符串而不是数字)。我的下一个问题是,如果某些数组项缺少键值,我该如何将这些项放在搜索列表的末尾?(所以假设您按“艺术家”排序,但第二个数组项没有“艺术家”键值)谢谢。 - Toniq
我建议避免这种补丁,而是在排序之前确保要排序的数据是一致的。 - KooiInc
2
它在Chrome浏览器上无法工作。我不知道为什么它表现与其他浏览器不同。它可以在Firefox,Safari和IE中运行。请提供任何关于此的建议,谢谢。 - Sai Durga
XP值是数字,而不是字母数字混合的。 - Phaedrus
1
它有一种奇怪的行为,不是100%的时间都能正常工作,可能取决于列表中有多少元素,请在此处检查代码片段:https://stackoverflow.com/questions/46582119/sorting-list-based-on-a-property-using-js-sort-function - Giox

8
function keysrt(key) {
  return function(a,b){
   if (a[key] > b[key]) return 1;
   if (a[key] < b[key]) return -1;
   return 0;
  }
}

someArrayOfObjects.sort(keysrt('text'));

2
看起来是Diode答案的重复(但从原型中删除),应该被删除。此外,请注意,这个算法会将“Unicorn”排在“astronaut”之前,因为大写字母的ASCII值比小写字母小(至少我认为是这样的 :) - Newclique

2
让您的生活变得简单,使用闭包 https://dev59.com/V2ox5IYBdhLWcg3w_ZV0#31846142 您可以在这里看到工作示例here
var filter = 'name', //sort by name
data = [{name:'bob', artist:'rudy'},{name:'johhny', artist:'drusko'},{name:'tiff', artist:'needell'},{name:'top', artist:'gear'}];; 

var compare = function (filter) {
    return function (a,b) { //closure
        var a = a[filter],
            b = b[filter];

        if (a < b) {
            return -1;
        }else if (a > b) {
            return 1;
        } else {
            return 0;
        }
    };
};

filter = compare(filter); //set filter

console.log(data.sort(filter));

1
为什么这会让生活更轻松?请解释一下。 - Newclique

1

看了所有答案后,我想出了一个跨浏览器的解决方案。被接受的解决方案在IE和Safari中不起作用。此外,其他解决方案不允许按降序排序。

/*! FUNCTION: ARRAY.KEYSORT(); **/
Array.prototype.keySort = function(key, desc){
  this.sort(function(a, b) {
    var result = desc ? (a[key] < b[key]) : (a[key] > b[key]);
    return result ? 1 : -1;
  });
  return this;
}

var arr = [{name:'bob', artist:'rudy'}, {name:'johhny', artist:'drusko'}, {name:'tiff', artist:'needell'}, {name:'top', artist:'gear'}];
arr.keySort('artist');
arr.keySort('artist', true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接