2012-11-14 60 views
1

我想知道如何创建一个自定义的sortOn函数,与某种排序优先级。我有一个更复杂的情况,但我主要想知道如何构建漂亮的排序函数。sortOn功能与优先

可以说我有这个无序列表与数据对象:

var myList = [ 
{drink: {amount: 1, name: "cola"}}, 
{drink: {amount: 5, name: "beer"}}, 
{food: {amount: 7, name: "cake"}}, 
{drink: {amount: 3, name: "fanta"}}, 
{drink: {amount: 4, name: "tea}}, 
{other: {amount: 1, name: "table"}}, 
{food: {amount: 4, name: "mars"}}, 
{food: {amount: 5, name: "pizza"}}, 
{food: {amount: 4, name: "cake"}}, 
{other: {amount: 12, name: "chair"}}, 
{food: {amount: 14, name: "chips"}}, 
{drink: {amount: 6, name: "coffee}}, 
{food: {amount: 8, name: "chips"}}, 
{food: {amount: 6, name: "pizza"}}, 
{food: {amount: 1, name: "food"}} 
] 

好,成像我想排序使用这些规则:

first: sort in this order: food, drinks, others (note, thats not alphabetical) 
    then: sort on amount, BUT on food, pizza's + cakes must be on top 

在理想情况下,它看起来像这样(手动创建):

var myList = [ 
{food: {amount: 5, name: "pizza"}}, 
{food: {amount: 6, name: "pizza"}}, 
{food: {amount: 4, name: "cake"}}, 
{food: {amount: 7, name: "cake"}}, 
{food: {amount: 1, name: "food"}}, 
{food: {amount: 4, name: "mars"}}, 
{food: {amount: 8, name: "chips"}}, 
{food: {amount: 14, name: "chips"}}, 
{drink: {amount: 1, name: "cola"}}, 
{drink: {amount: 3, name: "fanta"}}, 
{drink: {amount: 4, name: "tea}}, 
{drink: {amount: 5, name: "beer"}}, 
{drink: {amount: 6, name: "coffee}}, 
{other: {amount: 1, name: "table"}}, 
{other: {amount: 12, name: "chair"}} 
] 

再次,这完全不是一个现实世界的例子,但我有案件(前夕n更深的嵌套对象)我想要应用这样的规则。

是否有可能创建一些排序顺序查找列表(类似这样的),还是不可行?

priorityList = [ 
       food:[ 
       name:["pizza", "tea", rest], 
       amount: Array.ASCENDING} 
       ], 
       drink, 
       other 
      ]; // etc.. 

我想学习如何制作这样的排序功能。我喜欢看到一个Javascript或ActionScript的解决方案,但其他语言来说明也没关系。有这样的图书馆吗?我是否必须遍历所有项目,创建条件,在案例中推/不移或者是否可以使用自定义sort()函数?我需要一些指导如何以实用/有效的方式解决这个问题。

在此先感谢!

+0

['sort()'](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort)函数采用比较器参数。这是一个比较列表中两个元素的函数,sort()然后完成剩下的部分。 – millimoose

+0

@ ajax333221我修好了可乐,那是一个错字。 –

回答

1

你是对的,你必须返回-1,0或1,但这并不意味着你不能处理你内部的复杂排序,尽管这意味着你必须定制代码为你遇到的每一种情况。像这样的东西可以工作:

function myCustomSort(firstObject, secondObject):int 
{ 
    // Is firstObject a food and the second not? firstObject goes in front. 
    // Are both objects a food? 
     // Is firstObject's name pizza and the second not? 
     // firstObject goes in front. 
     //Are both objects' names pizza? Return 0 - they're equivalent. 
    //ETC. 
} 

理想情况下,虽然你想支持类似于你给出的架构的例子。我建议你做的结构相同的根,因为它是在孩子(这样你就可以运行在每个级别相同的代码),您的例子则是这个样子:

priorityList = { 
        "consumingType":[ 
         "food":{ 
         "name":[ 
          "pizza", 
          "tea" 
          ], 
         amount: Array.ASCENDING 
         }, 
         "drink", 
         "other" 
        ], 
        amount: Array.ASCENDING 
       }; 

实际的解决方案可能根据实际结构(您的数据是否使用JSON或对象)以及使用什么语言而略有不同 - 但这里是AS3 中的一个起步器,我尚未测试;这应该指向正确的方向。

首先,我会写一个处理排序的一层递归排序函数,然后检查是否有一个孩子层或退货:

function handleComplexSorting(sortingObject, first, second) { 
    var result:int = 0; 
    //Extracting the property name of first/second will differ, 
    //but pretty sure this is how you do it in AS3. 
    var firstValue:int = findSortValueForProperty(first[0], sortingObject[0]); 
    var secondValue:int = findSortValueForProperty(second[0], sortingObject[0]); 

    if(firstValue > secondValue) { 
     //firstValue should go first. 
     result = -1; 
    } 
    else if(firstValue < secondValue){ 
     //secondValue should go first. 
     result = 1; 
    } 
    else {//equal 
     var childSortingObject:Object; 
     if(hasChildSorting(sortingObject, childSortingObject)){ 
      //return result of recursion 
      result = handleComplexSorting(childSortingObject, first, second); 
     } 
     else { 
      result = 0; 
     } 
    } 
    return result; 
} 

的findSortValueForProperty功能会在您要添加上升/下降,我已经把它排除在外了,但是你只需要检查哪一个并且反转结果值。这里的值由它在数组中的索引的倒数决定(首先出现有最高值,最后有最低值,不存在 - 0值)。

function findSortValueForProperty(property:String, priorityProperties:Array):int { 
    var resultValue:int = 0; 
    var index = 0; 
    for each(var currentProperty:String in priorityProperties) { 
     if(property == currentProperty) { 
      resultValue = priorityProperties.length - index; 
      break; 
     } 
     ++index; 
    } 
    return resultValue; 
} 

最后,检查对象是否具有子分类要求。这实际上不起作用,它只是期望第一个项目可能有孩子排序。我也不是100%,你可以通过像我这样的索引访问对象的变量(sortingObject[0])(你可以肯定地遍历它们)。

function hasChildSorting(sortingObject:Object, outChild:Object):Boolean { 
    var result:Boolean = false; 
     if(sortingObject[0] is Object) { 
      result = true; 
      outChild = sortingObject[0]; 
     } 
    } 
    return result; 
} 

对于AS3具体见get string representation of a variable name in as3用于通过串存取的变量。 如果你想在别的地方做,你还需要你的语言reflection

+1

我特别没有说“最简单的解决方案是创建自定义排序功能”!最简单的解决方案是创建一个自定义的* compare *函数,这非常容易,然后使用内置的排序函数。 – Malvolio

+0

我已经删除了这句话。 – Jono

+0

另外,@Mark Kool:我指的是将它排序为两个对象之间的排序(即比较)。我的整个答案是一个自定义比较函数。 – Jono

2

你需要分离你脑海中的两个问题。

一个是排序:给出一个可比对象的列表,将它们从“最低”排序到“最高”。这是一个完全解决的问题。不要担心。

另一个是比较:给出两个对象,即“第一个”?考虑到你写的规范,以及任何两个对象,A和B,你可以说-1(对象A是第一个),0(它们相当于排序目的),或1(对象B是第一个)。

编写函数(使用您最喜欢的语言)并将其传递给语言的内置排序库以快速排序。

+0

谢谢,很高兴知道。但我认为我的问题在于我想要混合使用这个事实。我知道我的语言的排序功能,但我完全不知道如何处理多个比较规则并在一个排序函数内进行排序。所以我不知道什么时候应该传递-1,0或1.网上的大多数例子只比较一个属性,而不是这种特定的排序。 –

+0

你*不*要混合两者。排序取决于(并取决于*完全*)排序。您必须能够将问题简化为仅比较两个对象。 – Malvolio