Question

Picture an array with random access, such that if you remove one object from the array, all others after it are moved forward.

For example, say our array is of length five, but only contains 3 items, like so:

[A,B,C,null,null]

If we remove B, C is automatically moved forward resulting in:

[A,C,null,null,null]

Is there a common name for such a datastructure? Bonus upvote if you can name an existing mechanism in JavaScript/JQuery :)

Was it helpful?

Solution

Not to be glib but isn't the data structure just an array? You would use the slice method to remove the element and push to add the null value to the end.

OTHER TIPS

If you told me that you had a list that compacts its items toward the front as you describe, I would assume that it's a sorted list, or a list in which order matters. For example, when items are added they're always appended, so the items remain in their insertion order.

If order doesn't matter, then it's more efficient to replace the deleted item with the last item in the list. That is, given [A,B,C,D,null,null] and you delete B, you end up with [A,D,C,null,null,null].

A simple example of a custom object to do what you describe could be something like this.

Javascript

var MyBuffer = (function () {
    'use strict';

    /*jslint bitwise: true */
    var MAX_LENGTH = Math.pow(2, 32),
        MAX_LAST = MAX_LENGTH - 1,
        toStringFN = {}.toString,
        sliceFN = [].slice,
        toObject = {}.constructor;

    function isNumber(inputArg) {
        return toStringFN.call(inputArg) === '[object Number]';
    }

    function isString(inputArg) {
        return toStringFN.call(inputArg) === '[object String]';
    }

    function clamp(value, max) {
        return Math.min(Math.max(value, 0), max) >>> 0;
    }

    function fillHoles(array, length, value) {
        var index;

        for (index = 0; index < length; index += 1) {
            if (!array.hasOwnProperty(index)) {
                array[index] = value;
            }
        }

        return array;
    }

    function isNumeric(inputArg) {
        return (isNumber(inputArg) || isString(inputArg)) &&
            !isNaN(parseFloat(inputArg)) && isFinite(inputArg.toString().replace(/^-/, ''));
    }

    function checkType(inputArg) {
        if (!isNumeric(inputArg)) {
            throw new TypeError();
        }

        return inputArg;
    }

    function checkRange(value, max) {
        if (value < 0 && value > max) {
            throw new RangeError();
        }

        return value;
    }

    function ABuffer() {
        var args;

        if (!arguments.length) {
            this.buffer = [];
            this.length = 0;
            this.filler = null;
        } else {
            args = sliceFN.call(arguments);
            if (args.length === 1) {
                this.filler = null;
            } else {
                this.filler = args[1];
            }

            if (isNumeric(args[0])) {
                this.buffer = [];
                this.length = clamp(args[0], MAX_LENGTH);
            } else {
                this.buffer = sliceFN.call(toObject(args[0]));
                this.length = this.buffer.length;
            }
        }

        fillHoles(this.buffer, this.length, this.filler);
    }

    ABuffer.prototype = {
        clear: function () {
            this.buffer.length = 0;
            this.buffer.length = this.length;
            fillHoles(this.buffer, this.buffer.length, this.filler);

            return this;
        },

        resize: function (length) {
            checkRange(checkType(length), MAX_LAST);
            this.buffer.length = length = clamp(length, MAX_LENGTH);
            if (length > this.length) {
                fillHoles(this.buffer, this.buffer.length, this.filler);
            }

            this.length = length;

            return this;
        },

        assign: function (index, value) {
            var last = this.length - 1;

            checkRange(checkType(index), last);
            this.buffer[clamp(index, last)] = value;

            return this;
        },

        remove: function (index, howMany) {
            var last = this.length - 1,
                count;

            checkRange(checkType(index), last);
            count = this.buffer.splice(clamp(index, last), clamp(howMany, this.length) || 1).length;
            while (count) {
                this.buffer.push(this.filler);
                count -= 1;
            }

            return this;
        },

        item: function (index) {
            var last = this.length - 1;

            checkRange(checkType(index), last);

            return this.buffer[clamp(index, last)];
        },

        toString: function () {
            return JSON.stringify(this.buffer);
        },

        valueOf: function () {
            return this.buffer.slice();
        }
    };

    return ABuffer;
}());

var buffer = new MyBuffer({
    0: 'A',
    1: 'B',
    2: 'C',
    length: 5
});

/*global console */
console.log(buffer.toString());
buffer.remove(1, 2);
console.log(buffer.toString());
buffer.assign(3, 'X');
console.log(buffer.toString());
buffer.resize(10);
console.log(buffer.toString());
buffer.resize(5);
console.log(buffer.toString());
buffer.clear();
console.log(buffer.toString());

Output

["A","B","C",null,null]
["A",null,null,null,null]
["A",null,null,"X",null]
["A",null,null,"X",null,null,null,null,null,null]
["A",null,null,"X",null]
[null,null,null,null,null]

On jsFiddle

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top