javascriptarraystypescriptrecord

Shift data associated with an array's index based on filter data


I have an array of any values, as well as data associated with each value. This data is stored as Record<string,FooData> where the key is generated using the index within the array.

However, I am struggling to implement a correct solution for shifting the meta back to their correct place after the array has been filtered.

An example scenario: [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ]

The array is then filtered outside of my function. The old array is unknown, all that remains is the following data:

Knowing this information, how can I shift all records to their new location? ('h' moved from index 7 to 4)

I do not need to remove dangling data from the end of the array. All data in the record is from before the filter.

Reproducible Example

function getKey(i: number) {
   return `unknownProcess[${i}]`;
}

// Array before the filter
const originalArray = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ]
// Associated data is the upper case variant of the letter
const associatedData: Record<string, string> = {}
originalArray.forEach((letter, i) => {
  associatedData[getKey(i)] = letter.toUpperCase();
});
// data[getKey(0)] === 'A'
// data[getKey(2)] === 'C'

// Array after filter
// [ 'a', 'b', 'd', 'e', 'h', 'i', 'j' ]
// data[getKey(0)] === 'A'
// data[getKey(2)] === 'C' // should be 'D' now
// data[getKey(4)] === 'E' // should be 'H' now

type FooData = any

// separate file, cannot access data above
function shiftDataFromFilter(filteredArray: unknown[], data: Record<string, FooData>, removedIndeces: number[], lengthBeforeFilter: number) {
  // to get data of index 0
  const fooData = data[getKey(0)];
}

Solution

  • You can create a filtered indices array and then create a map object of filtered:original index:

    // const originalArray = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ]
    // const filteredArray = [ 'a', 'b', 'd', 'e', 'h', 'i', 'j' ];
    const lengthBeforeFilter = 10
    const removedIndices = [2,5,6];
    const removedIndicesSet = new Set(removedIndices);
    const filteredIndices = new Array(lengthBeforeFilter).fill(null).map((e,i)=>i).filter(e => !(removedIndicesSet.has(e)))
    const keyMap = filteredIndices.reduce((a,c,i)=>(a[i]=c,a),{});
    console.log(keyMap);

    With the keyMap, you can use

    data[getKey(keyMap[2])]
    

    to get the correct result or shift data accordingly.