2

I need to slice an array and enumerate the values but I also need the reference to the original index because I'm doing an async operation that needs to be mapped back to the original index in the original array when complete.

const array = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'];
const slicedArray = array.slice(0, 3).map((v, i) => ({ v, i }));
// Returns: [{ "v": "foo", "i": 0 }, { "v": "bar", "i": 1 }, { "v": "baz", "i": 2 }]
// Required: [{ "v": "foo", "i": 0 }, { "v": "bar", "i": 1 }, { "v": "baz", "i": 2 }]
const slicedArray2 = array.slice(3, 6).map((v, i) => ({ v, i }));
// Returns: [{ "v": "qux", "i": 0 }, { "v": "quux", "i": 1 }, { "v": "corge", "i": 2 }]
// Required: [{ "v": "qux", "i": 3 }, { "v": "quux", "i": 4 }, { "v": "corge", "i": 5 }]

How can I achieve this?

eozzy
  • 66,048
  • 104
  • 272
  • 428
  • 1
    First map *then* slice, if you want the original indexes. Or add an offset to the index. – VLAZ Jan 11 '22 at 10:54
  • Perhaps, you need to just wait for a bunch of promises to resolve in parallel? For this, use [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) – Parzh from Ukraine Jan 11 '22 at 10:54
  • @DimaParzhitsky Yes, I'm using `Promise.allSettled` but I wouldn't know the original index because slice always resets it right? @VLAZ Not ideal, the original array is quite large. – eozzy Jan 11 '22 at 10:56
  • Yes, slice "resets" the index, since it just makes a new array. However, `Promise.allSettled()` wouldn't alter the order of items. If you do `Promise.allSettled(foo(arr.slice(0, 3)), foo(arr.slice(3, 6)))` you'd get back two arrays where the first one corrsponds to indexes 0-2, the second one to indexes 3-5. It shouldn't be hard to match the result to the original. You can grab all results and `.concat()` them into an array that will match the original (or can overwrite it, for example). – VLAZ Jan 11 '22 at 11:02

3 Answers3

2

The items in the slice always have indexes that are exactly startIndex less than in the original array:

slice(0, 3) -> [0, 1, 2] -> [0 - 0, 1 - 0, 2 - 0]
slice(3, 6) -> [0, 1, 2] -> [3 - 3, 4 - 3, 5 - 3]
slice(n, …) -> [0, 1, …] -> [n + 0 - n, n + 1 - n, n + 2 - n, …]

So, just adding startIndex back should do the trick:

/**
 * @template Item
 * @param {Item[]} items
 * @param {number} startIndex
 * @param {number} [endIndex]
 * @returns {Array<{ item: Item; index: number }>}
 */
function slice(items, startIndex, endIndex = items.length) {
    return items.slice(startIndex, endIndex).map((item, index) => ({
        item,
        index: index + startIndex,
    }));
}

function slice(items, startIndex, endIndex = items.length) {
  return items.slice(startIndex, endIndex).map((item, index) => ({
    item,
      index: index + startIndex,
  }));
}

const letters = [ ...'abcdefghijklmnopqrstuvwxyz' ];

console.log(slice(letters, 0, 3));
console.log(slice(letters, 3, 6));
console.log(slice(letters, 6, 9));
Parzh from Ukraine
  • 7,999
  • 3
  • 34
  • 65
2

Using array.map() You can get the all array value and index ! After this use .slice()

Try this code it's help you

 const array = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'];
 const slicedArray2 = array.map((v, i) => ({ v, i })).slice(3, 6);
 console.log(slicedArray2, 'slicedArray2');
Mayur Vaghasiya
  • 1,383
  • 2
  • 12
  • 24
0

I actually like the accepted answer better, but for the record another solution without the slice

const data = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'];

const slice = (items, startIndex, endIndex = items.length) => {
  return items.reduce((acc, v, i) => {
    if (i >= startIndex && i < endIndex )
      acc.push({ v, i })
    return acc;
  }, []);
}

console.log(slice(data, 0, 3));
console.log(slice(data, 3));
.as-console-wrapper{min-height: 100%!important; top: 0}
A1exandr Belan
  • 4,442
  • 3
  • 26
  • 48