在Javascript中使用特定异常对对象数组进行排序

时间:2015-03-20 11:27:25

标签: javascript arrays algorithm sorting

我有一个对象数组,其中一些元素是另一个元素的克隆,因此它们具有引用原始元素的另一个属性的属性(简化示例):

var a = [{
    id: 'x0',
    name: 'Foo',
    isClone: false,
    wasCloned: true,
    originalId: ''
}, {
    id: 'y1',
    name: 'Bar'.
    isClone: false,
    wasCloned: false,
    originalId: ''
}, {
    id: 'z2',
    name: 'Foo',
    isClone: true,
    wasCloned: false,
    originalId: 'x0'
}];

在这个例子中,第三个元素引用第一个元素的id - 这使它成为这个意义上的克隆。不幸的是,id不是增量/时间顺序的,基本上可以是任意随机字符串。

现在,手头的任务是以这样的方式对数组进行排序,以便克隆始终放置在数组位置右之前其原始位置。如果数组元素不是克隆,则排序应该照常进行。换句话说,一旦排序,此示例中的顺序将为 2,0,1

我试图弄清楚如何使用Array.sort来解决这个问题,但却无法真正理解它。这基本上就是我所拥有的(它不起作用):

var sortedA = a.sort(function(one, other) {
    var sorted;
    if (one.id == other.originalId) {
        sorted = -1;
    } else {
        sorted = 0;
    }
    return sorted;
});

非常感谢您对此的任何帮助。谢谢。

3 个答案:

答案 0 :(得分:2)

您应该使用以下排序功能:

var sorted = a.sort(
    function (a, b) {
        var compareA = a.originalId || a.id;
        var compareB = b.originalId || b.id;

        if (compareA < compareB) {
            return -1;
        } else if (compareA > compareB) {
            return 1;
        } else {
            return a.originalId !== '' ? -1 : 1;
        }
    }
);

可以使用功能工作的一个示例here

答案 1 :(得分:1)

  1. 获取具有原始ID的所有对象,并保存没有的对象。

    var others = [];
    var data = a.filter(function(elem) {
        if (elem.originalID !== '') {
            return true;
        } else {
            others.push(elem); // keep a trace of elements without originalID
            return false;
        }    
    });
    
  2. 对它们进行排序,使它们全部打包在一起

    data.sort(function(a, b) {
        return a.originalID.localeCompare(b.originalID); //compare string
    });
    
  3. 现在,您将所有包含相同originalID的元素打包在一起。 然后,我们只需要在每个打包元素的末尾添加带有id的元素,并使用相同的originalID

    var originId = data[0].originalID; //get the first origin id
    for(var i = 0; i < data.length; i++) {
       var elem = data[i];
       //the end of a packed list
       if(originID !== elem.originalID) {
           var val = others.find(function(e, index) { //find the element with the good id
               if(return e.id === originID) {
                   others.splice(index, 1);//remove the element from the others array
                   return true;
               } else {
                   return false;
               }
           });
    
           data.splice(i, 0, val[0]); //insert it at the end of the packed list
           originID = elem.originalID; //save for next loop
       }
    }
    
    
    
    //just need to add the remaing element to the list
    var final = data.concat(others);
    console.log(final);
    

    确实可以改进(添加支票,减少工作量),但我认为你有了这个想法。

答案 2 :(得分:1)

我的解决方案与GreenLeaf相似。它会创建一个新数组,而不是修改原始数据,这对您来说可能是也可能不是问题。

方法是首先删除克隆。然后,如果需要,可以对数组进行排序,然后最终将克隆插入其原始对象上方:

// create a new array without any clones, save the clones 
var clonesMap = {};
var aWithoutClones = a.filter(function(item){
    if (item.isClone) {
        if (!clonesMap[item.originalId]) {
            clonesMap[item.originalId] = [];
        }
        clonesMap[item.originalId].push(item);
        return false;
    }

    return true;
});

// here you can sort aWithoutClones

// put all clones back before their original object
a = [];
for (var i = 0; i < aWithoutClones.length; i++) {
    var currId = aWithoutClones[i].id;
    if (clonesMap[currId]){
        a = a.concat(clonesMap[currId]);
    }
    a.push(aWithoutClones[i]);
}

我认为这可以为您提供更大的灵活性,因为您现在有机会对数组进行排序而无需考虑克隆。此外,您还可以使用单独的排序功能对克隆进行排序。