Last active
May 1, 2021 09:02
-
-
Save revolunet/5702041 to your computer and use it in GitHub Desktop.
Python-like JS slice
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/** | |
* @ngdoc function | |
* @name ng.filter:slice | |
* @function | |
* | |
* @description | |
* Creates a new array limited to the specified range, and optionnaly extracts only n-th items | |
* with the `step` argument, similar to Python slice operators. | |
* The array can also be reversed easily depending on the sign of the `step` parameter. | |
* The slice function uses the builtin Javscript `array.slice` method. | |
* | |
* Note: This function is used to augment the `Array` type in Angular expressions. See | |
* {@link ng.$filter} for more information about Angular arrays. | |
* | |
* @param {Array} input Source array to be sliced. | |
* @param {number} start Slice start index. If the `start` number | |
* is positive, the slice will start at index `start`. | |
* If the `start` number is negative, the slice will start from the n-th item | |
* from the end of the source array. | |
* @param {number} end Slice end index. If the `end` number | |
* is positive, the slice will end at index `end` exluded. | |
* If the `end` number is negative, the slice will end at the n-th item | |
* from the end of the source array. | |
* @param {number} step Slice items step. If the `step` number | |
* is specified, the function will only return each n-th item based on its index. | |
* If the `step` number is negative, the slice will be reversed and we return | |
* each n-th item in reversed order. | |
* @returns {Array} A new sub-array containing `Math.floor(end-start/step)`/ | |
* | |
* @example | |
<doc:example> | |
<doc:source> | |
<script> | |
function Ctrl($scope) { | |
$scope.numbers = [1,2,3,4,5,6,7,8,9]; | |
$scope.start = 3; | |
$scope.end = 7; | |
$scope.step = 1; | |
} | |
</script> | |
<div ng-controller="Ctrl"> | |
Start at: <input type="integer" ng-model="start"><br> | |
End at: <input type="integer" ng-model="end"><br> | |
Step: <input type="integer" ng-model="step"><br> | |
<p>Output numbers: {{ numbers | slice:start:end:step }}</p> | |
</div> | |
</doc:source> | |
<doc:scenario> | |
it('should limit the number array to first three items', function() { | |
expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3'); | |
expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3'); | |
expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]'); | |
expect(binding('letters | limitTo:letterLimit')).toEqual('abc'); | |
}); | |
it('should update the output when -3 is entered', function() { | |
input('numLimit').enter(-3); | |
input('letterLimit').enter(-3); | |
expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]'); | |
expect(binding('letters | limitTo:letterLimit')).toEqual('ghi'); | |
}); | |
it('should not exceed the maximum size of input array', function() { | |
input('numLimit').enter(100); | |
input('letterLimit').enter(100); | |
expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]'); | |
expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi'); | |
}); | |
</doc:scenario> | |
</doc:example> | |
*/ | |
function slice(array, from, to, step) { | |
if (from===null) from=0; | |
if (to===null) to=array.length; | |
if (!step) return array.slice(from, to); | |
var result = Array.prototype.slice.call(array, from, to); | |
if (step < 0) result.reverse(); | |
step = Math.abs(step); | |
if (step > 1) { | |
var final = []; | |
for (var i = result.length - 1; i >= 0; i--) { | |
(i % step === 0) && final.push(result[i]); | |
}; | |
final.reverse(); | |
result = final; | |
} | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment