0

我想知道是否如何创建具有某种排序优先级的自定义 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"}}
]

同样,这完全不是一个真实的例子,但我有一些案例(甚至更深的嵌套对象)我想应用这样的规则。

是否可以创建某种排序顺序查找列表(类似这样),还是不可行?

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

我想学习如何制作这种排序功能。我喜欢看 Javascript 或 Actionscript 解决方案,但其他语言也可以说明。有这方面的图书馆吗?我是否必须遍历所有项目、创建条件、在情况下推送/取消移位,或者这是否可以通过自定义sort()函数实现?我需要一些指导如何以实用/有效的方式解决这个问题。

提前致谢!

4

2 回答 2

2

你需要在脑海中把这两个问题分开。

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

另一个是比较:给定两个对象,哪个是“第一个”?鉴于您编写的规范以及任意两个对象 A 和 B,您可以说 -1(对象 A 是第一个)、0(它们在排序方面是等效的)或 1(对象 B 是第一个)。

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

于 2012-11-14T20:54:45.450 回答
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,请参阅在 as3 中获取变量名的字符串表示,以通过字符串访问变量。如果您想在其他方面进行反思,您还需要您的语言进行反思。

于 2012-11-14T22:39:46.543 回答