2015-04-17 29 views
9
阵列由另一个内容

说我有Person对象的数组:排序在JavaScript

var people = [{name: "Joe Schmo", age: 36}, {name: "JANE DOE", age: 40}]; 

和我有可以排序字符串箱子的阵列不区分大小写的函数:

function caseInsensitiveSort(arr) { ... } 

是否有任何直接的方法来结合我现有的排序功能Array.prototype.map排序people阵列只使用name键?

I.e.它会产生

var people = [{name: "JANE DOE", age: 40}, {name: "Joe Schmo", age: 36}]; 

做手工也不是很难在这种特殊情况下,

people.sort(function (a, b) { 
    return a.name.localeCompare(b.name); 
}); 

,但我想不出这样做的一种方式,让我用预现有的排序功能。在排序功能更加定制的情况下,这将是有用的。

编辑:我相信这里的核心问题是要做到这一点,你需要能够弄清楚当你对代理数组进行排序时,原始索引被映射到了什么位置。在一般情况下,使用JS的本地sort函数获得这些新索引似乎不可能。但我很乐意被证明是错误的。

编辑:我试图做到这一点的方式效率太低,无法使用。请参阅下面的答案,使用比较函数替代解决方案。

+0

如果'caseInsensitiveSort'接受一个数组,你需要在名称的数组给该函数的名称进行排序,然后基于与名称阵列上的对象数组排序。听起来像是一种非常复杂的方式来做简单的事情。 – adeneo

+0

它会处理几个元素吗?因为'Array.prototype.map'方法创建一个新数组,所以对于数百万条记录来说,最好的选择就是对它进行就地排序。 –

+0

@adeneo @Jordan你们俩都是对的。正如xdazz在下面指出的,正确的方法是将我的比较逻辑抽象为一个单独的函数,并将其提供给'Array.prototype.sort',而不是试图将我的排序函数放入。 –

回答

4

你可以使用你现有的功能得到排序名称数组,然后通过索引排序的名字排列在比较people数组进行排序。

var names = caseInsensitiveSort(people.map(function(person) { 
    return person.name; 
})); 

people.sort(function (a, b) { 
    return names.indexOf(a.name) - names.indexOf(b.name); 
}); 

但是,这是没有效率的,你应该尝试抽象出比较逻辑从caseInsensitiveSort功能为caseInsensitiveCompare功能。

然后你的榜样将成为:

people.sort(function (a, b) { 
    return caseInsensitiveCompare(a.name, b.name); 
}); 
+0

每次迭代使用'indexOf'两次会使这个数组变得相当缓慢,但这可能是以一般方式完成它的唯一可能方式。 +1。 –

+1

@ChrisMiddleton你不能从'caseInsensitiveSort'函数中抽象比较逻辑吗? – xdazz

+0

是的,你是对的。这是我想的真正答案。要以通用和有效的方式完成此操作,您需要在比较函数级别工作,而不是排序函数。谢谢。 –

1

根据您的caseInsensitiveSort()功能是如何工作的,你可以利用一个.toString()的方法来做到这一点:

var toSort = people.map(function (person) { 
    return { 
     person: person, 
     toString: function() { 
      return person.name; 
     } 
    }; 
}); 

caseInsensitiveSort(toSort); 

people = toSort.map(function (item) { return item.person; }); 

如果这不是一个选项,一个混乱但仍然有效的方法是再排序基于这些名称进行排序,它们映射到自己的索引和:

var names = people.map(function (person) { return person.name; }); 

caseInsensitiveSort(names); 

var nameMap = {}; 
names.forEach(function (name, i) { 
    nameMap[name] = i; 
}); 

people.sort(function (a, b) { 
    return nameMap[a.name] - nameMap[b.name]; 
}); 
+0

感谢您的补充 - 您的第二个解决方案与我在询问时的想法类似。它当然只适用于你正在排序的值是可关键值的情况,但这可能是一个不可避免的限制,除非你使用散列值作为非可键值。 –

+0

@ChrisMiddleton是的,这当然是对的。它适用于名称,但不适用于所有类型的值。 – JLRishe