HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Implementing Python-like slice in JavaScript

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
javascriptlikepythonimplementingslice

Problem

Python has by far the best slice implementation I've ever used. As a quick evening project I felt like trying to implement Python's slice construct in a JavaScript function (thinking about sending a pr to a certain library with Python's slice semantics). I came up with the code below, and I'm trying to improve my code. I would love feedback or alternative implementations.

I think I hit all the edge cases, but I only briefly skimmed the Python source, so I could easily be wrong.

``
/**
* Implementation of Python's
slice` function... Get a cloned subsequence
* of an iterable (collection with length property and array like indexs).
* Will handle both strings and array(likes).
*
* @param {Array|String} collection
* @param {None|Integer} start First index to include. If negative it will be indicies from end
(i.e. -1 is last item). Omit or pass 0/null/undefined for 0.
* @param {None|Integer} end Last index to include. If negative it will be indicies from end
(i.e. -1 is last item). Omit or pass null/undefined for end.
* @param {None|Intger} step Increments to increase by (non-1 will skip indicies). Negative values
will reverse the output.
* @returns {Array|String} sliced array
*
* @example
* var list = [1, 2, 3, 4, 5]
* slice(list) // => [1, 2, 3, 4, 5]
* slice(list, 2) // => [3, 4, 5]
* slice(list, 2, 4) // => [3, 4]
* slice(list, -2) // => [4, 5]
* slice(list, null, -1) // => [1, 2, 3, 4]
* slice(list, null, null, 2) // => [1, 3, 5]
* slice(list, null, null, -2) // => [5, 3, 1]
* slice("kids a devil I tell ya", 7, -10, -1) // => "lived"
*/
function slice(collection, start, end, step) {
var length = collection.length,
isString = typeof collection == "string", // IE length) {
end = length;
} else if (end 0) {
for (; start < end; start += step) {
result.push(collection[start]);
}
} else {
for (end

Solution

Throwing errors

You should only throw errors, not strings.

throw new Error("Slice step cannot be zero");


Leveraging existing API

What you're doing looks very similar to the existing slice except for the last parameter, step. This could be more compact if you used built-in slice for everything and then apply the step afterward.

function slice(collection, start, end, step) {
    var slice = collection.slice || Array.prototype.slice,
        sliced = slice.call(collection, start, end),
        result, length, i;

    if (!step) {
        return sliced;
    }
    result = [];
    length = sliced.length;
    i = (step > 0) ? 0 : length - 1;
    for (; i = 0; i += step) {
        result.push(sliced[i]);
    }
    return typeof collection == "string" ? result.join("") : result;
}


This would require you to pass undefined in the places you have null in your usage examples. If you want to be able to pass null, you can add if (start === null) start = undefined, and the same for end.

Code Snippets

throw new Error("Slice step cannot be zero");
function slice(collection, start, end, step) {
    var slice = collection.slice || Array.prototype.slice,
        sliced = slice.call(collection, start, end),
        result, length, i;

    if (!step) {
        return sliced;
    }
    result = [];
    length = sliced.length;
    i = (step > 0) ? 0 : length - 1;
    for (; i < length && i >= 0; i += step) {
        result.push(sliced[i]);
    }
    return typeof collection == "string" ? result.join("") : result;
}

Context

StackExchange Code Review Q#57268, answer score: 3

Revisions (0)

No revisions yet.