按其相对位置对数组进行排序

时间:2018-02-16 09:47:58

标签: javascript sorting

示例对象数组:

[{
    id: 'a',
    beforeId: null
}, {
    id: 'b',
    beforeId: 'c'
}, {
    id: 'c',
    beforeId: 'a'
}, {
    id: 'd',
    beforeId: 'b'
}]

输出顺序:d-b-c-a;每个元素根据其beforeId属性相对于每个其他元素进行排序。

我可以创建一个临时数组并对上面的数组进行排序。可以使用array.sort进行排序吗?

4 个答案:

答案 0 :(得分:7)

您可以使用关系构建一个对象,并使用beforeId: null对象生成结果,并取消结果数组的所有对象。

下一个对象是实际val作为键的对象。

复杂性:O(2n)。



function chain(array) {
    var o = {}, pointer = null, result = [];

    array.forEach(a => o[a.beforeId] = a);

    while (o[pointer]) {
        result.unshift(o[pointer]);
        pointer = o[pointer].val;
    }

    return result;
}

var data = [{ val: 'a', beforeId: null }, { val: 'b', beforeId: 'c' }, { val: 'c', beforeId: 'a' }, { val: 'd', beforeId: 'b' }];

console.log(chain(data));

.as-console-wrapper { max-height: 100% !important; top: 0; }




答案 1 :(得分:4)

这是一种非常低效且天真的算法,但它有效:

const array = [
    {id: 'a', beforeId: null},
    {id: 'b', beforeId: 'c'},
    {id: 'c', beforeId: 'a'},
    {id: 'd', beforeId: 'b'}
];

// find the last element
const result = [array.find(i => i.beforeId === null)];

while (result.length < array.length) {
    // find the element before the first element and prepend it
    result.unshift(array.find(i => i.beforeId == result[0].id));
}

console.log(result);

答案 2 :(得分:1)

  

是否可以使用array.sort进行排序?

确定,有辅助功能:

graph = [
    {id: 'a', beforeId: null},
    {id: 'b', beforeId: 'c'},
    {id: 'c', beforeId: 'a'},
    {id: 'd', beforeId: 'b'}
];

let isBefore = (x, y) => {
    for (let {id, beforeId} of graph) {
        if (id === x)
            return (beforeId === y) || isBefore(beforeId, y);
    }
    return false;
};

graph.sort((x, y) => x === y ? 0 : (isBefore(x.id, y.id) ? -1 : +1))

console.log(graph);

如果isBeforex之前立即或传递,则

y会返回true。

对于通用的非线性拓扑排序,请参阅https://en.wikipedia.org/wiki/Topological_sorting#Algorithms

UPD:正如here所示,结果证明效率非常低,因为sort涉及许多不必要的比较。这是迄今为止最快的(迄今为止)版本:

function sort(array) {
    let o = {}, res = [], len = array.length;

    for (let i = 0; i < len; i++)
        o[array[i].beforeId] = array[i];

    for (let i = len - 1, p = null; i >= 0; i--) {
        res[i] = o[p];
        p = o[p].id;
    }

    return res;
}

这是@Nina的想法,针对速度进行了优化。

答案 3 :(得分:0)

您可以尝试这种方法:

// order(null, vals, []) = ["d", "b", "c", "a"]
function order(beforeId, vals, result){
    var id = beforeId || null;

    var before = vals.filter(function(val){
                return val.beforeId ===  id
    });

    if (before.length === 0) return result;   

    return order(before[0].val,
                    vals, 
                [before[0].val].concat(result));
}