sort函数中的递归

时间:2015-08-24 17:51:03

标签: javascript arrays sorting recursion

我有一个巨大的比较函数,我用它来对具有数字和字符串值的2D数组进行排序,我想让它变小。我已经在彼此内部重复使用了相同的代码块,我认为这是多余的。我想我可以使用递归使代码更小但我认为我之前没有这样做过,而且我的sort函数似乎非常复杂。它如下:

check if a & b is array
check if a & b is number or string
    if number
        check if a equals to b
            repeat same process with different index
    if string
        check if a equals to b
            repeat same process with different index

示例数组:

var artists = [
    ["Katy Perry",          "3",    "9"     ],
    ["Enrique Iglesias",    "3",    "9"     ],
    ["Taylor Swift",        "2",    "9"     ],
    ["Evanescence",         "4",    "10"    ],
    ["Bruno Mars",          "1",    "5"     ],
    ["Shania Twain",        "3",    "12"    ],
    ["Amanda Abizaid",      "2",    "2"     ],
    ["Death Cab For Cutie", "2",    "2"     ],
    ["Simple Plan",         "1",    "2"     ],
];

// sort and prioritize columns by 2, 1, 0, sort order for each 1 = asc
artists.sort(compare.bind([2, 1, 0], [1, 1, 1]));

排序后的相同数组:

var artists = [
    ["Simple Plan",         "1",    "2"     ],
    ["Amanda Abizaid",      "2",    "2"     ],
    ["Death Cab For Cutie", "2",    "2"     ],
    ["Bruno Mars",          "1",    "5"     ],
    ["Taylor Swift",        "2",    "9"     ],
    ["Enrique Iglesias",    "3",    "9"     ],
    ["Katy Perry",          "3",    "9"     ],
    ["Evanescence",         "4",    "10"    ],
    ["Shania Twain",        "3",    "12"    ],
];

实际比较功能:

// compare is passed to Array.prototype.sort
// array2bSorted.sort(sortable.compare.bind([cols, orders]));

compare : function(a, b) {

    var columns = sortable.explodeInnerArrays(this[0]);
    var orders  = sortable.explodeInnerArrays(this[1]);

    var primaryA = a[columns[0]];
    var primaryB = b[columns[0]];

    if (primaryA instanceof Array) {
        primaryA = a[columns[0]][0];
    }
    if (primaryB instanceof Array) {
        primaryB = b[columns[0]][0];
    }

    switch (sortable.checkDataType(primaryA)) {
        case "number":
            if (primaryA == primaryB && columns.length > 1) {

                var secondaryA = a[columns[1]];
                var secondaryB = b[columns[1]];

                if (secondaryA instanceof Array) {
                    secondaryA = a[columns[1]][0];
                }
                if (secondaryB instanceof Array) {
                    secondaryB = b[columns[1]][0];
                }

                switch (sortable.checkDataType(secondaryA)) {
                    case "number":
                        if (secondaryA == secondaryB && columns.length > 2) {

                            var tertiaryA = a[columns[2]];
                            var tertiaryB = b[columns[2]];

                            if (tertiaryA instanceof Array) {
                                tertiaryA = a[columns[2]][0];
                            }
                            if (tertiaryB instanceof Array) {
                                tertiaryB = b[columns[2]][0];
                            }

                            switch (sortable.checkDataType(tertiaryA)) {
                                case "number":
                                    return (tertiaryA - tertiaryB) * orders[2];
                                    break;
                                case "string":
                                    tertiaryA = sortable.removePunctuation(tertiaryA);
                                    tertiaryB = sortable.removePunctuation(tertiaryB);
                                    if (tertiaryA < tertiaryB) {
                                        return -1 * orders[2];
                                    }
                                    if (tertiaryA > tertiaryB) {
                                        return 1 * orders[2];
                                    }
                                    return 0;
                                    break;
                            }
                        }
                        return (secondaryA - secondaryB) * orders[1];
                        break;
                    case "string":
                        if (secondaryA == secondaryB && columns.length > 2) {

                            var tertiaryA = a[columns[2]];
                            var tertiaryB = b[columns[2]];

                            if (tertiaryA instanceof Array) {
                                tertiaryA = a[columns[2]][0];
                            }
                            if (tertiaryB instanceof Array) {
                                tertiaryB = b[columns[2]][0];
                            }

                            switch (sortable.checkDataType(tertiaryA)) {
                                case "number":
                                    return (tertiaryA - tertiaryB) * orders[2];
                                    break;
                                case "string":
                                    tertiaryA = sortable.removePunctuation(tertiaryA);
                                    tertiaryB = sortable.removePunctuation(tertiaryB);
                                    if (tertiaryA < tertiaryB) {
                                        return -1 * orders[2];
                                    }
                                    if (tertiaryA > tertiaryB) {
                                        return 1 * orders[2];
                                    }
                                    return 0;
                                    break;
                            }
                        }
                        secondaryA = sortable.removePunctuation(secondaryA);
                        secondaryB = sortable.removePunctuation(secondaryB);
                        if (secondaryA < secondaryB) {
                            return -1 * orders[1];
                        }
                        if (secondaryA > secondaryB) {
                            return 1 * orders[1];
                        }
                        break;
                }
            }
            return (primaryA - primaryB) * orders[0];
            break;
        case "string":
            if (primaryA == primaryB && columns.length > 1) {

                var secondaryA = a[columns[1]];
                var secondaryB = b[columns[1]];

                if (secondaryA instanceof Array) {
                    secondaryA = a[columns[1]][0];
                }
                if (secondaryB instanceof Array) {
                    secondaryB = b[columns[1]][0];
                }

                switch (sortable.checkDataType(secondaryA)) {
                    case "number":
                        if (secondaryA == secondaryB) {

                            var tertiaryA = a[columns[2]];
                            var tertiaryB = b[columns[2]];

                            if (tertiaryA instanceof Array) {
                                tertiaryA = a[columns[2]][0];
                            }
                            if (tertiaryB instanceof Array) {
                                tertiaryB = b[columns[2]][0];
                            }

                            switch (sortable.checkDataType(tertiaryA)) {
                                case "number":
                                    return (tertiaryA - tertiaryB) * orders[2];
                                    break;
                                case "string":
                                    tertiaryA = sortable.removePunctuation(tertiaryA);
                                    tertiaryB = sortable.removePunctuation(tertiaryB);
                                    if (tertiaryA < tertiaryB) {
                                        return -1 * orders[2];
                                    }
                                    if (tertiaryA > tertiaryB) {
                                        return 1 * orders[2];
                                    }
                                    return 0;
                                    break;
                            }
                        }
                        return (secondaryA - secondaryB) * orders[1];
                        break;
                    case "string":
                        if (secondaryA == secondaryB && columns.length > 2) {

                            var tertiaryA = a[columns[2]];
                            var tertiaryB = b[columns[2]];

                            if (tertiaryA instanceof Array) {
                                tertiaryA = a[columns[2]][0];
                            }
                            if (tertiaryB instanceof Array) {
                                tertiaryB = b[columns[2]][0];
                            }

                            switch (sortable.checkDataType(tertiaryA)) {
                                case "number":
                                    return (tertiaryA - tertiaryB) * order;
                                    break;
                                case "string":
                                    tertiaryA = sortable.removePunctuation(tertiaryA);
                                    tertiaryB = sortable.removePunctuation(tertiaryB);
                                    if (tertiaryA < tertiaryB) {
                                        return -1 * orders[2];
                                    }
                                    if (tertiaryA > tertiaryB) {
                                        return 1 * orders[2];
                                    }
                                    return 0;
                                    break;
                            }
                        }
                        secondaryA = sortable.removePunctuation(secondaryA);
                        secondaryB = sortable.removePunctuation(secondaryB);
                        if (secondaryA < secondaryB) {
                            return -1 * orders[1];
                        }
                        if (secondaryA > secondaryB) {
                            return 1 * orders[1];
                        }
                        break;
                }

            }
            primaryA = sortable.removePunctuation(primaryA);
            primaryB = sortable.removePunctuation(primaryB);
            if (primaryA < primaryB) {
                return -1 * orders[0];
            }
            if (primaryA > primaryB) {
                return 1 * orders[0];
            }
            break;
    }
},

比较函数按多个列对数组进行排序,每个列都有自己的排序顺序。由于列是在数组中传递的,因此初始索引具有更高的优先级。

Working fiddle

使用递归我提出了以下代码,但它不起作用。数组未排序。它也不会抛出任何错误。 (我删除了一些不相关的部分,使其看起来更简单)

compare : function(a, b) {

    var columns = sortable.explodeInnerArrays(this[0]);
    var orders  = sortable.explodeInnerArrays(this[1]);

    function loop(a, b, index) {

        var currentA = a[columns[index]];
        var currentB = b[columns[index]];

        switch (sortable.checkDataType(currentA)) {
            case "number":
                if (currentA == currentB) {
                    loop(a, b, (index+1));
                }
                return (currentA - currentB) * orders[index];
                break;
            case "string":
                if (currentA == currentB) {
                    loop(a, b, (index+1));
                }
                if (currentA < currentB) {
                    return -1 * orders[index];
                }
                if (currentA > currentB) {
                    return 1 * orders[index];
                }
                break;
        }
    }

    loop(a,b,0);
}

我错过了什么?

2 个答案:

答案 0 :(得分:0)

我设法解决了问题,并创建了我的第一个递归。

简单地在loop内调用compare函数不会做任何事情,因为它会将1-1返回到compare函数并{{1}函数不会返回任何内容。我需要返回compare函数返回的值。 loop成功了。

return loop(a, b, index)

答案 1 :(得分:-1)

  

我已经在if和switch语句中多次使用相同的代码块,我认为这是多余的。

在尝试跳转到递归之前,首先尝试重构:首先使用Extract Method将重复的代码移动到自己的函数中。