[SOLVED] JavaScript performance for iterating and accessing items

Issue

I have an array of items which I sometimes need to iterate and sometimes access a member directly. So I decided to keep references in two variables, one array and one object. I do something like this:

const itemsArr = [];
const itemsObj = {};
const addItem = (data) => {
    const item = {
        id: data.id,
        name: data.name
    };
    itemsArr.push(item);
    itemsObj[data.id] = item;
}

const removeItem = (data) => {
    let i;
    for (i = 0; i < itemsArr.length; i++) {
        if (itemsArr[i].id === data.id) {
            itemsArr.splice(i, 1);
            break;
        }
    }
    itemsObj[data.id] = null;
    delete itemsObj[data.id];
}

const getWithId = (id) => {
    return itemsObj[id];
}

const getWithName = (name) => {
    let i;
    for (i = 0; i < itemsArr.length; i++) {
        if (itemsArr[i].name === name) {
            return itemsArr[i];
        }
    }
    return null
}

So I manage two objects and use one or another depending on the task, I feel like this is the most performant way but maybe there are better ways for this, like a Map or Set.

Is there a single JavaScript data structure that will outperform arrays in iteration and objects in lookup?

I think Object.keys have additional performance costs for iterating an object, similarly Array.filter for lookup on an array, so my intuition is to use arrays for iteration and objects for lookup, but if there is a single data structure that is optimized for both, I would like to know and use only one items in my code.

Thanks

Solution

First, for the lookup-by-id part of things, I’d suggest a Map, not an object. Objects are optimized for the common programming use case where their set of properties is fairly consistent over time (the values may change, but the shape of the object [what properties it has] mostly doesn’t). Map is optimized as a general name/value store that handles that use case better. More in on this MDN page.

Is there a single Javascript data structure that will outperform arrays in iteration and objects in lookup?

No, but the difference in iteration speed between a Map and an array won’t matter in the vast majority of applications. Yes, an array will be faster in most cases (it depends a bit on how the array is built), but it’s just really unlikely to matter.

But if you only ever access by id or name, you aren’t iterating anyway. You might want two maps rather than a map and an array, since that way finding items either way is sublinear rather than linear. It also makes for simpler code:

const itemsByName = new Map();
const itemsById = new Map();
const addItem = (data) => {
    const item = {
        id: data.id,
        name: data.name
    };
    itemsByName.set(data.name, data);
    itemsByid.set(data.id, data);
};

const removeItem = (data) => {
    itemsByName.delete(data.name);
    itemsByid.delete(data.id);
};

const getWithId = (id) => {
    return itemsById.get(id);
};

const getWithName = (name) => {
    return itemsByName.get(name);
};

FWIW, if you didn’t have itemsByName in the above because you didn’t need name lookup to be sublinear, here’s what the code for getWithName would look like using itemsById:

const getWithName = (name) => {
    for (const item of itemsById.values()) {
        if (data.name === name) {
            return data;
        }
    }
    return null;
};

Answered By – T.J. Crowder

Answer Checked By – Terry (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *