4

there are many questions/answers dealing with this topic. None match my specific case. Hopefully someone can help:

I have an array of indexes such as:

var indexes = [24, 48, 32, 7, 11];

And an array of objects that look similar to this:

var items = [{
              name : "whatever",
              selected : false,
              loading : true,
              progress : 55,
              complete : false
},
{
              name : "whatever 2",
              selected : false,
              loading : false,
              progress : 100,
              complete : true
}];

Each integer within the indexes array corresponds to the actual index of an object within the items array.

Lastly I have a variable which defines the new insert position within the items array:

 var insertindex = ??

What I would like to do is to take all objects in the items array that have the indexes stored in the indexes array, remove them, then finally place them back, all next to each other at a specified index defined by the variable insertindex.

I have been trying to use splice() by copying the objects at each index to a temporary array, then removing them from the original array, then finally looping through this new temporary array and putting them back into the original items array at the new positions, but seems to be hitting a mental brick wall and cannot get it to work correctly.

To summarize, I simply want to take all objects from the items array that match an index defined in the indexes array, put them together and reinsert them at a predefined index, back into the items array.

To help with conceptual visualization. If you think of the app as a javascript file manager, allowing the reordering of multiple file selections which do not have to be adjacent. The indexes array defining the current selection and the items array defining the list of files. And finally the rearoderindex defines the new insert position that all selected files should move to.

EDIT: As was rightly suggested here is the code I am playing with right now:

function reorder(items, indexes, insertindex){

        var offset = 0;
        var itemscopy = items.slice(0); //make shallow copy of original array
        var temparray = new Array(); // create temporary array to hold pulled out objects

        //loop through selected indexes and copy each into temp array
        for(var i=0, len=indexes.length; i<len; i++){ 
            array[i] = itemscopy[self.cache.selecteditems[i]];
        }


        //remove all selected items from items array
        for(var i=0, len=indexes.length; i<len; i++){
            items.splice(indexes[i], 1);
        }

        //finally loop through new temp array and insert the items back into the items array at the specified index, increasing the index each iteration using the offset variable.
        for(var i=0, len=temparray.length; i<len; i++){
            items.splice((insertindex+offset), 0, array[i]);
            offset++;
        }

}

I'm aware this is pretty horrible and that looping three times should not be necessary. But I've been trying lots of different methods, some working when reordering in one direction, some in the other an mostly, not at all. I figured I would look to optimize the function later, once I have it working with accuracy.

I'm certain I must be doing something extremely stupid or completely overlooking something, but for the life of me I can't work out what right now.

1
  • 4
    Post the splice code you have, or better yet, make a JSFiddle. That sounds like the right track to me. Commented Mar 25, 2013 at 16:20

2 Answers 2

5

If you don't care about order of indexes array, I'd suggest another short solution:

items.splice.apply(items, [insertIndex, 0].concat(indexes.sort(function(a, b) {
    return a - b;
})).map(function(i, p) {
    return p > 1 ? items.splice(i - p + 2, 1).pop() : i;
}));

DEMO: http://jsfiddle.net/T83fB/

To make it short I used Array.map() method, which is not supported by old IE browsers. However it is always easy to use a shim from MDN.

Sign up to request clarification or add additional context in comments.

1 Comment

This is lovely, a very elegant solution! Thanks VisioN. I'll test it thoroughly later on and reaward in the answer to yourself if it turns out to be the best solution :) many thanks!
2

You can use the .splice() function to add elements to an array, as well as removing items from it. The general principle is:

  1. Sort indexes into ascending numeric order
  2. Iterate over indexes, removing the element at that index (adjusting for the number of removed items) and storing it in a removedItems array
  3. Add the removedItems array back in at the required index

The code to do that would look something like this:

var removedItems = [];
// sort indexes
indexes.sort(function(a, b) {
    if(a < b) return -1;
    else if(b < a) return 1;
    return 0;
});
for(var i = 0; i < indexes.length; i++) {
    var index = indexes[i];
    removedItems.push(items.splice(index - removedItems.length, 1));
}
var insertIndex = 1;
items.splice.apply(items, [insertIndex, 0].concat(removedItems));

Take a look at this jsFiddle demo.

4 Comments

This works absolutely perfectly! :) Fantastic. the system has also provided an answer which under minimal testing seems to work also. Any chance you could comment on which you feel is the best/most performant solution, before I award the answer? Regardless many thanks. Thats a huge help.
@gordyr So does that mean that you don't care about order of indexes array elements?
@VisioN In this case, no. Since the items (files) are displayed, left to right, top to bottom as the index increases, sorting them into ascending order is the correct behavior for my use case. It's worth noting however that in addition to Anthony's answer I have had to test how many of the selected codeindexes values are less than the 'code'insertindex and offset the insert position by that amount. Meaning that I can reorder a selection of files that consists of items from the beginning of the array and from the end of the array into an insert point somewhere in the middle
@gordyr If so, I have added my version, which is a bit shorter and does not use additional resources.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.