Czy w JavaScript jest funkcja podobna do tej w Pythonie range()
?
Myślę, że powinien być lepszy sposób niż pisanie za każdym razem następujących wierszy:
array = new Array();
for (i = 0; i < specified_len; i++) {
array[i] = i;
}
javascript
python
clwen
źródło
źródło
range()
działania w Pythonie, więc możesz z niej korzystać. W JavaScript nie ma takiej funkcji, ale jest kilka wtyczek dla różnych frameworków, takich jakRange
klasa dla MooTools .Odpowiedzi:
Nie , nie ma, ale możesz to zrobić .
Implementacja języka Python w JavaScript
range()
Próbując emulować jak to działa w Pythonie , stworzyłbym funkcję podobną do tej:
function range(start, stop, step) { if (typeof stop == 'undefined') { // one param defined stop = start; start = 0; } if (typeof step == 'undefined') { step = 1; } if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) { return []; } var result = []; for (var i = start; step > 0 ? i < stop : i > stop; i += step) { result.push(i); } return result; };
Zobacz to jsfiddle, aby uzyskać dowód.
Porównanie między
range()
JavaScript i PythonDziała to w następujący sposób:
range(4)
zwroty[0, 1, 2, 3]
,range(3,6)
zwroty[3, 4, 5]
,range(0,10,2)
zwroty[0, 2, 4, 6, 8]
,range(10,0,-1)
zwroty[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
,range(8,2,-2)
zwroty[8, 6, 4]
,range(8,2)
zwroty[]
,range(8,2,2)
zwroty[]
,range(1,5,-1)
zwroty[]
,range(1,5,-2)
zwroty[]
,a jego odpowiednik w Pythonie działa dokładnie w ten sam sposób (przynajmniej we wspomnianych przypadkach):
>>> range(4) [0, 1, 2, 3] >>> range(3,6) [3, 4, 5] >>> range(0,10,2) [0, 2, 4, 6, 8] >>> range(10,0,-1) [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] >>> range(8,2,-2) [8, 6, 4] >>> range(8,2) [] >>> range(8,2,2) [] >>> range(1,5,-1) [] >>> range(1,5,-2) []
Jeśli więc potrzebujesz funkcji działającej podobnie do Pythona
range()
, możesz skorzystać z powyższego rozwiązania.źródło
stop
jest większe niżstart
(i zamień je, jeśli nie).start >= stop
prowadzenie do pustej tablicy jest konieczne, jeśli celem jest rzeczywiście emulacja zakresu Pythona. I uważam, że i tak jest bardziej intuicyjny.start >= stop
nie wystarczy, aby ta funkcja zachowywała się jakrange()
w Pythonie. Zaktualizowałem moją odpowiedź.Dla bardzo prostego zakresu w ES6:
let range = n => Array.from(Array(n).keys())
Z komentarza bigOmega można to skrócić za pomocą składni Spread :
let range = n => [...Array(n).keys()]
źródło
let range = n => [...Array(n).keys()]
const
jak najwięcej, ale tutaj będzie to tylko odniesienie do tablicy, więc tablica nadal byłaby edytowalna: 'Dconst
to samej funkcji, a nie jej wartości zwracanej. Prawdopodobnie nie chcesz w żaden sposób modyfikować funkcji.2018: ta odpowiedź wciąż zyskuje na popularności, więc oto aktualizacja. Poniższy kod jest przestarzały, ale na szczęście standardowe generatory ES6 i
yield
słowo kluczowe są powszechnie obsługiwane na różnych platformach. Przykład leniwegorange()
używaniayield
można znaleźć tutaj .Oprócz tego, co już zostało powiedziane, Javascript 1.7+ zapewnia obsługę iteratorów i generatorów, które mogą być używane do tworzenia leniwej, wydajnej pamięciowo wersji programu podobnego
range
doxrange
w Pythonie2:function range(low, high) { return { __iterator__: function() { return { next: function() { if (low > high) throw StopIteration; return low++; } } } } } for (var i in range(3, 5)) console.log(i); // 3,4,5
źródło
step
argument i przetestować go na wartościach z mojej odpowiedzi ? Twoja odpowiedź jest świetna w przypadku aplikacji, dla których mamy na myśli bardzo specyficzne przeglądarki (nie będzie działać w Google Chrome, Safari i IE w wersjach wcześniejszych niż 9: stackoverflow.com/a/2209743/548696 ).range
ma wykluczoną „ostatnią” wartość (więc należy użyć jej>=
zamiast>
w powyższym kodzie)Łącząc obie odpowiedzi z @Tadeck i @georg , wymyśliłem to:
function* range(start, stop, step = 1) { if (stop == null) { // one param defined stop = start; start = 0; } for (let i = start; step > 0 ? i < stop : i > stop; i += step) { yield i; } }
Aby użyć go w pętli for, potrzebujesz pętli for-of ES6 / JS1.7:
for (let i of range(5)) { console.log(i); } // Outputs => 0 1 2 3 4 for (let i of range(0, 10, 2)) { console.log(i); } // Outputs => 0 2 4 6 8 for (let i of range(10, 0, -2)) { console.log(i); } // Outputs => 10 8 6 4 2
źródło
step
parametru, ale gdystop
nie jest przekazywany, obastart
istop
muszą zostać zmienione. Zaktualizuję toPort
range
funkcji z Pythona 2 jest udostępniany przez biblioteki narzędziowe underscore.js i lodash (wraz z wieloma innymi przydatnymi narzędziami). Przykłady skopiowane z podkreślonych dokumentów:_.range(10); => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] _.range(1, 11); => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] _.range(0, 30, 5); => [0, 5, 10, 15, 20, 25] _.range(0, -10, -1); => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] _.range(0); => []
źródło
Można to osiągnąć, dołączając iterator do
Number
prototypuNumber.prototype[Symbol.iterator] = function* () { for (var i = 0; i <= this; i++) { yield i } } [...5] // will result in [0,1,2,3,4,5]
Zaczerpnięte z kursu Kyle'a Simpsona Rethinking Asynchronous JavaScript
źródło
Oto małe rozszerzenie jednej z odpowiedzi na wypadek, gdybyś musiał określić zarówno początkową, jak i końcową pozycję zakresu:
let range = (start, end) => Array.from(Array(end + 1).keys()).slice(start);
źródło
Proszę bardzo.
Spowoduje to zapisanie (lub nadpisanie) wartości każdego indeksu wraz z numerem indeksu.
Array.prototype.writeIndices = function( n ) { for( var i = 0; i < (n || this.length); ++i ) this[i] = i; return this; };
Jeśli nie podasz liczby, użyje bieżącej długości tablicy.
Użyj tego w ten sposób:
var array = [].writeIndices(10); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
źródło
Dalsze udoskonalenie dzięki domyślnym parametrom ES6.
let range = function*(start = 0, stop, step = 1) { let cur = (stop === undefined) ? 0 : start; let max = (stop === undefined) ? start : stop; for (let i = cur; step < 0 ? i > max : i < max; i += step) yield i }
źródło
Aby uzyskać tablicę rozmiarów
x
, oto jedna linijka bez użycia żadnej bibliotekivar range = n => Array(n + 1).join(1).split('').map((x, i) => i)
pracuje jako
> range(4) [0, 1, 2, 3]
źródło
var range = n => Array(n).fill().map((e, i) => i);
x
”, kiedy faktycznien
używałeś nazwy parametruPoniżej przedstawiono naturalną adaptację funkcji range () języka Python do JavaScript:
// Generate range from start (inclusive) to stop (exclusive): function* range(start, stop, step = 1) { if (stop === undefined) [start, stop] = [0, start]; if (step > 0) while (start < stop) yield start, start += step; else if (step < 0) while (start > stop) yield start, start += step; else throw new RangeError('range() step argument invalid'); } // Examples: console.log([...range(3)]); // [0, 1, 2] console.log([...range(0, 3)]); // [0, 1, 2] console.log([...range(0, 3, -1)]);// [] console.log([...range(0, 0)]); // [] console.log([...range(-3)]); // [] console.log([...range(-3, 0)]); // [-3, -2, -1]
Obsługuje żadnego argumentu, który można porównać do
0
astop
i może być zwiększana ostep
. Zachowuje się identycznie jak wersja Pythona, gdy jest używana z liczbami nieprzekraczającymiNumber.MAX_SAFE_INTEGER
.Zwróć uwagę na następujące przypadki narożne:
[...range(0, 0, 0)]; // RangeError: range() step argument invalid [...range(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 2)]; // [] [...range(Number.MAX_SAFE_INTEGER + 2, Number.MAX_SAFE_INTEGER + 3)]; // Infinite loop [...range(0.7, 0.8, 0.1)]; // [0.7, 0.7999999999999999] [...range('1', '11')]; // ['1'] [...range('2', '22')]; // Infinite loop
W przeciwieństwie do @ Tadeck użytkownika , @ Volv użytkownika i użytkownika @ janka102 odpowiedź których powrót
[]
,undefined
albo wejść w nieskończoną pętlę, gdystep
ocenia się0
czyNaN
funkcja ta generator zgłasza wyjątek podobny do zachowania Pythona.źródło
pythonic
naśladujerange
zachowanie Pythona najlepiej, jak potrafi, używając generatorów JS (yield
), obsługujących zarówno przypadki użycia , jakrange(stop)
irange(start, stop, step)
. Ponadto,pythonic
jestrange
funkcja zwracaIterator
obiekt podobny do Pythona, który obsługujemap
ifilter
tak można zrobić fantazyjny jednej wkładki, takich jak:import {range} from 'pythonic'; // ... const results = range(5).map(wouldBeInvokedFiveTimes); // `results` is now an array containing elements from // 5 calls to wouldBeInvokedFiveTimes
Zainstaluj za pomocą
npm
:npm install --save pythonic
Ujawnienie Jestem autorem i opiekunem Pythonic
źródło
MDN zaleca takie podejście: Generator sekwencji (zakres)
// Sequence generator function (commonly referred to as "range", e.g. Clojure, PHP etc) const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step)); // Generate numbers range 0..4 console.log("range(0, 4, 1):", range(0, 4, 1)); // [0, 1, 2, 3, 4] // Generate numbers range 1..10 with step of 2 console.log("\nrange(1, 10, 2):", range(1, 10, 2)); // [1, 3, 5, 7, 9] // Generate the alphabet using Array.from making use of it being ordered as a sequence console.log("\nrange('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x))", range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x))); // ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
źródło
Możesz użyć biblioteki podkreślenia . Zawiera dziesiątki przydatnych funkcji do pracy z tablicami i wiele innych.
źródło
Wszystkie przedstawione tutaj rozwiązania odnoszą się do zakresu Pythona 2 (prawdopodobnie z powodu podanego przykładu kodu). Jednak w Pythonie 3 metoda range () zwraca iterator. JavaScript ma również iteratory i są one bardziej wydajne pod względem miejsca niż generowanie całej tablicy i przechowywanie jej w pamięci.
Tak więc dokładniejsza reprezentacja funkcji Pythona 3
range(n)
toArray(n).keys()
.Na przykład:
for (let i of Array(n).keys()) { console.log(i) // 0, 1, 2, 3, ..., n }
Jeszcze jeden przykład (który został już omówiony w innych odpowiedziach). Konwersja iteratora na tablicę (ES6):
let ary = [...Array(n).keys()]; // ary = [0, 1, 2, 3, ..., n]
źródło
Wciąż nie ma wbudowanej funkcji, która
range()
byłaby równoważna , ale w najnowszej wersji - ES2015 - możesz zbudować własną implementację. Oto jego ograniczona wersja. Ograniczone, ponieważ nie uwzględnia parametru kroku. Tylko min, max.const range = (min = null, max = null) => Array.from({length:max ? max - min : min}, (v,k) => max ? k + min : k)
Osiąga się to za pomocą
Array.from
metody zdolnej do zbudowania tablicy z dowolnego obiektu, który malength
właściwość. Zatem przekazanie prostego obiektu tylko z tąlength
właściwością utworzy ArrayIterator, który dostarczylength
liczbę obiektów.źródło
To jest mój ulubiony sposób. Umożliwia określenie jednego lub dwóch danych wejściowych, jak w Pythonie.
function range(start, end) { return Array.from(Array(end||start).keys()).slice(!!end*start) }
źródło
Oto kolejna
es6
realizacja tej serii// range :: (from, to, step?) -> [Number] const range = (from, to, step = 1) => { //swap values if necesery [from, to] = from > to ? [to, from] : [from, to] //create range array return [...Array(Math.round((to - from) / step))] .map((_, index) => { const negative = from < 0 ? Math.abs(from) : 0 return index < negative ? from + index * step : (index - negative + 1) * step }) } range(-20, 0, 5) .forEach(val => console.log(val)) for(const val of range(5, 1)){ console.log(`value ${val}`) }
źródło
-20
do-30
?Nie, nie ma, ale możesz to zrobić.
Jestem stronniczy w zachowaniu range w Pythonie3. Poniżej znajdziesz implementację zakresu Pythona () w JavaScript:
function* range(start=0, end=undefined, step=1) { if(arguments.length === 1) {end = start, start = 0} [...arguments].forEach(arg => { if( typeof arg !== 'number') {throw new TypeError("Invalid argument")} }) if(arguments.length === 0) {throw new TypeError("More arguments neede")} if(start >= end) return yield start yield* range(start + step, end, step) } // Use Cases console.log([...range(5)]) console.log([...range(2, 5)]) console.log([...range(2, 5, 2)]) console.log([...range(2,3)]) // You can, of course, iterate through the range instance.
źródło
Zakładając, że potrzebujesz prostego zakresu z jednym krokiem:
let range = (start, end)=> { if(start === end) return [start]; return [start, ...range(start + 1, end)]; }
jeszcze
let range = (start, end, step)=> { if(start === end) return [start]; return [start, ...range(start + step, end)]; }
zajrzyj tutaj po więcej.
źródło
Jak odpowiedziałem wcześniej: nie , nie ma. Ale możesz zrobić własne. Uważam, że jest to interesujące podejście do ES6. Działa bardzo podobnie do Pythona 2.7
range()
, ale jest znacznie bardziej dynamiczny.function range(start, stop, step = 1) { // This will make the function behave as range(stop) if(arguments.length === 1) { return [...Array(arguments[0]).keys()] } // Adjusts step to go towards the stop value if((start > stop && !(step < 0)) || (start < stop && !(step > 0))) { step *= -1 } let returnArray = [] // Checks if i is in the interval between start and stop no matter if stop // is lower than start or vice-versa for(let i = start; (i-start)*(i-stop) <= 0; i += step) { returnArray.push(i) } return returnArray }
Ta funkcja może działać na trzy różne sposoby (podobnie jak zakres () w Pythonie):
range(stop)
range(start, stop)
range(start, stop, step)
Te przykłady:
console.log(range(5)) console.log(range(-2, 2)) console.log(range(2, -2)) console.log(range(10, 20, 2))
Da ci następujące dane wyjściowe:
[ 0, 1, 2, 3, 4 ] [ -2, -1, 0, 1, 2 ] [ 2, 1, 0, -1, -2 ] [ 10, 12, 14, 16, 18, 20 ]
Zauważ, że zamiast iterować po tablicy za pomocą
in
operatora (jak python), musisz użyćof
. W ten sposóbi
zmienna przyjmuje wartość, a nie indeks, elementu tablicy.for(let i of range(5)) { // do something with i... }
źródło
Opcją dla NodeJs jest użycie bufora:
[...Buffer.alloc(5).keys()] // [ 0, 1, 2, 3, 4 ]
Fajne jest to, że możesz iterować bezpośrednio w buforze:
Buffer.alloc(5).forEach((_, index) => console.log(index)) // 0 // 1 // 2 // 3 // 4
Nie możesz tego zrobić z niezainicjowaną tablicą:
Array(5).forEach((_, index) => console.log(index)) // undefined
Ale kto przy zdrowych zmysłach używa bufora do takiego celu;)
źródło
function range(start, stop) { if (typeof stop == 'undefined') { stop = start; start = 0; } result = [...Array(stop).keys()].slice(start, stop); return result; }
źródło
Oto jak to robię
let n = 5 [...Array(n).keys()].map(x=>{console.log(x)})
wynik
źródło