简体   繁体   中英

How can I move multiple items in an array to different index in an Array?

I have an array with 7 items in it. I want to move a few items to a different index in the same order as it was in the original array. I have pasted in code snippet on whatever I tried so far.

 let originalArray = ['a','b','c','d','e','f','g']; let itemsToBeMoved = ['c','f','e']; let newIndexToBeMoved = 4; //expected result is ['a','b','d','c','e','f','g']; let movableItemsIndex = []; movableItemsIndex.push(originalArray.indexOf('c')); movableItemsIndex.push(originalArray.indexOf('f')); movableItemsIndex.push(originalArray.indexOf('e')); //To be Moved items has to be sorted as in originalArray movableItemsIndex.sort(); let itemsToBeMovedSorted = [originalArray[movableItemsIndex[0]],originalArray[movableItemsIndex[1]],originalArray[movableItemsIndex[2]]]; //Removing items before inserting to items to new position while(movableItemsIndex.length) { originalArray.splice(movableItemsIndex.pop(), 1); } let newUpdatedArray = [...originalArray],j=0; for(let i = newIndexToBeMoved;i < originalArray.length; i++){ newUpdatedArray[i] = itemsToBeMovedSorted[j]; j++; } console.log(newUpdatedArray);

Assuming that all elements are unique:

 let originalArray = ['a','b','c','d','e','f','g']; let itemsToBeMoved = ['c','f','e']; let newIndexToBeMoved = 4; // find the value of the element the marks the insertion point let insertBefore = originalArray[newIndexToBeMoved]; // in original sequence order, check for presence in the removal // list, *and* remove them from the original array let moved = []; for (let i = 0; i < originalArray.length; ) { let value = originalArray[i]; if (itemsToBeMoved.indexOf(value) >= 0) { moved.push(value); originalArray.splice(i, 1); } else { ++i; } } // find the new index of the insertion point let insertionIndex = originalArray.indexOf(insertBefore); if (insertionIndex < 0) { insertionIndex = originalArray.length; } // and add the elements back in originalArray.splice(insertionIndex, 0, ...moved); console.log(originalArray);

This can be solved many ways, but here is a quick run-down of what could be done:

  1. First, you could create a "present" map (based on the positions in the source array) for the items to be moved
  2. Now, filter the array, removing the items, but keeping track whether they are present
  3. Splice the (sorted) present, filtered-out, values into the altered array at the desired position (based on the index in the source array)

 const move = (arr, items, index) => { const present = new Map(items.map(item => [item, arr.indexOf(item)])); const altered = arr.filter(item => !present.has(item)); altered.splice(arr.indexOf(arr[index - 1]), 0, ...([...present.entries()] .filter(([k, v]) => v !== -1) .sort(([, k1], [, k2]) => k1 - k2) .map(([k, v]) => k))); return altered; } const moved = move(['a','b','c','d','e','f','g'], ['c','f','e'], 4); console.log(moved);
 .as-console-wrapper { top: 0; max-height: 100% !important; }

Here's a way to do it with typescript and generics . It does not mutate the array, it's very fast (used the conclusions of this article to make it).

When moving items to a new position, there is always a range of items affected by the move. By affected, I mean that within that range, all items will have to move. I calculate the min/max of the range, any items outside that range will simply be copied from the old to new array.

Then, depending whether the items are moved up or down in the array, I copy each items from old to new array taking into account the offset of the move.

export const arrayMove = <ItemType>({
    arr,
    from,
    to,
    movedItemsCount = 1,
}: {
    arr: ItemType[]
    from: number
    to: number
    movedItemsCount?: number
}) => {
    if (from === to) return arr

    const minAffected = Math.min(from, to)
    const maxAffected = Math.max(to, from + movedItemsCount - 1)
    const pushedItemsCount = maxAffected - minAffected + 1 - movedItemsCount

    const newArr: ItemType[] = []
    newArr.length = arr.length

    for (let i = 0; i < arr.length; i++) {
        if (i < minAffected || i > maxAffected) {
            // When i is outside the affected range,
            // items are identical in new and old arrays
            newArr[i] = arr[i]
        } else {
            // Moving items down
            if (to > from) {
                if (i < to - movedItemsCount + 1) {
                    // Write pushed items
                    newArr[i] = arr[i + movedItemsCount]
                } else {
                    // Write moved items
                    newArr[i] = arr[i - pushedItemsCount]
                }
            } else {
                // Moving items up
                if (i < to + movedItemsCount) {
                    // Write moved items
                    newArr[i] = arr[i + pushedItemsCount]
                } else {
                    // Write pushed items
                    newArr[i] = arr[i - movedItemsCount]
                }
            }
        }
    }

    return newArr
}

Try this:

 const originalArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; const itemsToBeMoved = ['c', 'f', 'e']; const newIndexToBeMoved = 4; originalArray.splice(newIndexToBeMoved, 0, itemsToBeMoved) console.log(originalArray.flat())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM