Search code examples
javascriptarraysjavascript-objects

Best way to reference data objects by in-line key according to separate sequence array?


An indexedDB getAll request returns an array data of objects, each with a two-dimensional in-line key such as { 'key' : [2,5], ... }. All the keys have the same key[0] and the array is returned sorted by key[1]; however, the key[1] can have gaps, due to the user having created a record and then subsequently deleting it. A back-fill method is used to re-use deleted keys but that can never ensure there are not gaps.

An array seq containing the sequence in which the data objects are to be displayed is also provided. It is an array of key[1] values.

I want to step through the sequence array, each time getting the record from the data-object array with the matching key[1] value.; but there is no direct map. For example, the sequence array could be [10,4,7,1,3,5,9] and the data array will be [ { 'key' : [n,1], ...}, { ['key' : [n,3],...}, { 'key' : [n,4],...}, { 'key' : [n,5],...}, { 'key' : [n,7],...}, { 'key' : [n,9],...}, { 'key' : [n,10],...} ]. Thus, when the third object to be displayed is that of key[1] = 7, I need to know that it is the fifth element in the data array.

I have been using an object to map, such as:

k = new Object();
data.forEach( ( v, i ) => { k[ v.key[1] ] = i; } );

And using it to reference as:

seq.forEach( (v, i ) => { e = data[ k[ v ] ]; } );

or

for ( i = 0; i < seq.length; i++ ) { e = data[ k[ seq[i] ] ]; };

Is there a better way? Thank you.


Update after thinking a bit and realizing how stupid I can be at times.

Sometimes I can be so stupid. I thought I got off track in looking at this simple issue as a task of coming up with some sort of index mapping between the seq and data arrays; and thought all that is required is to sort data by key[1] according to the sequence order provided in the seq array of key[1] values. In a sense that is correct.

Thus, object k would not be needed and data could be sorted in place, so to speak. I thought k was a copy of array data with property names equal to the desired index, and that the approach was not efficient. However, as @barmar points out below, k does not contain a copy of the objects in data but only their references. And bulding an object of references should be more efficient than sorting the array in place and actually 'moving' the data. I assume it is similar to using pointers.

I included the snippet of the sort below just for illustration, even though it is likely not as efficient, because it was interesting to someone at my lower level to build a sort function based off of an object property. The snippet illustrates how to take the example I provided to ask this question and sort it in place based on sequence order in seq. It's nothing new or novel. You'll see that data is in key[1] order as in seq and the property p are in increasing numerical order from 1 to 7 indicating their desired positions just for illustration.

Thank you.

var seq = [10,4,7,1,3,5,9],

    data = [ { 'key' : [5,1], 'p' : 4 },
             { 'key' : [5,3], 'p' : 5 },
             { 'key' : [5,4], 'p' : 2 },
             { 'key' : [5,5], 'p' : 6 },
             { 'key' : [5,7], 'p' : 3 },
             { 'key' : [5,9], 'p' : 7 },
             { 'key' : [5,10], 'p' : 1 } ];
             
data.sort( ( a, b ) => { return seq.indexOf( a.key[1] ) - seq.indexOf( b.key[1] ); } );

console.log( data );


Solution

  • Don't put the index in k, put the object itself.

    data.forEach(v => k[v.key[1]] = v);