递归排序功能

时间:2019-04-17 15:33:57

标签: javascript angular typescript

我有一个功能,可以根据一组键对一组对象进行排序。这些键具有一个优先级,sortKey和一个布尔值,以判断其是升序还是降序。我遇到的问题是,当您有重复的条目并且只有一个键时,它会在调用索引+1的递归函数时抛出错误,但是没有其他键,因此该键未定义。

这是失败的测试:

it('Should sort with one priority and duplicate entries', () => {
    const arr = [{letter: 'a'}, {letter: 'b'}, {letter: 'a'}];
    const keys: ISortPriority<any>[] = [{sortKey: 'letter', priority: 1, ascending: true}];
    expect(sortObjectsByKey(arr, keys)).toEqual([{letter: 'a'}, {letter: 'a'}, {letter: 'b'}]);
});

这是我用来排序的代码:

   export function sortObjectsByKey<T>(arrayToSort: T[], sortByKeys: ISortPriority<T>[]): T[] {
       return arrayToSort.sort((a, b) => {
           return sortWithKey(a, b, sortByKeys, 0);
       });
   }

   function sortWithKey<T>(a: T, b: T, keys: ISortPriority<T>[], index: number) {
       keys = keys.sort((c, d) => (c.priority > d.priority) ? 1 : -1);
       const currKey = keys[index].sortKey;
       if (keys[index].ascending) {
           return a[currKey] > b[currKey]
               ? 1
               : (
                   a[currKey] < b[currKey]
                       ? -1
                       : sortWithKey(a, b, keys, index + 1)
               );
       }
       return a[currKey] < b[currKey]
           ? 1
           : (
               a[currKey] > b[currKey]
                   ? -1
                   : sortWithKey(a, b, keys, index + 1)
           );

    }


我尝试添加其他条件,例如:

 return a[currKey] > b[currKey] ? 1 : (a[currKey] < b[currKey] ? -1 : a[currKey] === b[currKey] ? 0 : sortWithKey(a, b, keys, index + 1));

但这会导致其他测试失败。

1 个答案:

答案 0 :(得分:0)

如果在尝试使用index < keys.length - 1之前对sortKeys的数量添加测试(sortWithKey(a, b, keys, index + 1)),该代码将起作用。

下面的正确实现(在es6中)和带有2个键的测试:

// emulates jest's it
function it(description, test) {
    console.log(description);
    test();
}
// test function
function equals(v1, v2) {
    if (v1 == null && v2 == null) {
        return true;
    }
    if (v1 == null || v2 == null) {
        return false;
    }
    if (typeof v1 !== typeof v2) {
        console.log('fail because', v1, ' and ', v2, 'are not of the same type');
        return false;
    }
    if (typeof v1 === 'object') {
        if (Array.isArray(v1)) {
            // eslint-disable-next-line no-use-before-define
            const res = arrayEquals(v1, v2);
            if (!res) {
              console.log('fail because', v1, '!==', v2);
            }
            return res;
        }
        // eslint-disable-next-line no-use-before-define
        return objectEquals(v1, v2);
    }
    const res = v1 === v2;
    if (!res) {
      console.log('fail because', v1, '!==', v2);
    }
    return res;
}
// test function
function arrayEquals(array1, array2) {
    if (array1.length !== array2.length) {
      console.log('fail because array1 and array2 do not have the same length');
      return false;
    }
    for (let i = 0; i < array1.length; i += 1) {
        if (!equals(array1[i], array2[i])) {
            console.log('fail because', array1[i], '!==', array2[i]);
            return false;
        }
    }
    return true;
}
// test function
function objectEquals(obj1, obj2) {
    const keys1 = Object.keys(obj1);
    if (keys1.length !== Object.keys(obj2).length) {
        console.log('fail because array1 and array2 do not have the same number of keys');
        return false;
    }
    for (let i = 0; i < keys1.length; i += 1) {
        const key = keys1[i];
        if (!equals(obj1[key], obj2[key])) {
            console.log('fail because', obj1[key], '!==', obj2[key]);
            return false;
        }
    }
    return true;
}
// emulates jest's expect
function expect(t) {
    return {
        toEqual: (v) => {
            const res = equals(t, v);
            if (res) {
                console.log(`expect ${JSON.stringify(t)} to equals ${JSON.stringify(v)}: Success`);
            } else {
                console.log(`expect ${JSON.stringify(t)} to equals ${JSON.stringify(v)}: Fail`);
            }
        }
    };
}

function sortWithKey(a, b, keys, index) {
    // eslint-disable-next-line no-param-reassign
    keys = keys.sort((c, d) => (c.priority > d.priority ? 1 : -1));
    const currKey = keys[index].sortKey;
    if (keys[index].ascending) {
        return a[currKey] > b[currKey]
            ? 1 :
            (
                a[currKey] < b[currKey]
                    ? -1
                    : (
                        index < keys.length - 1
                            ? sortWithKey(a, b, keys, index + 1)
                            : 0
                    )
            );
    }
    return a[currKey] < b[currKey]
        ? 1
        : (
            a[currKey] > b[currKey]
                ? -1
                : (
                    index < keys.length - 1
                        ? sortWithKey(a, b, keys, index + 1)
                        : 0
                )
        );
}

function sortObjectsByKey(arrayToSort, sortByKeys) {
    return arrayToSort.sort((a, b) => sortWithKey(a, b, sortByKeys, 0));
}

it('Should sort with two priorities and duplicate entries', () => {
    const arr = [{ letter: 'a', n: 1 }, { letter: 'b', n: 1 }, { letter: 'c', n: 0 }, { letter: 'b', n: 0 }, { letter: 'a', n: 0 }];
    const keys = [{ sortKey: 'letter', priority: 1, ascending: false }, {sortKey: 'n', priority: 2, ascending: true}];
    expect(sortObjectsByKey(arr, keys)).toEqual([{"letter":"c","n":0},{"letter":"b","n":0},{"letter":"b","n":1},{"letter":"a","n":0},{"letter":"a","n":1}]);
});

就像其他人所说的那样,它缺乏加德条件,并且在每次递归调用时对键进行重新排序都有点滥用,但是您应该从那里开始。