imperative vs declarative JavaScript - javascript

I am doing an exercise about imperative vs declarative. Unfortunately I don't understand the example or I don't get any results. "Uncaught ReferenceError: range is not defined"
'use strict'
// imperative
let numbers = range(10)
let evenNumbers = []
for (let i = 0; i < numbers.length; i += 1) {
if (numbers[i] % 2 === 0) {
evenNumbers.push(numbers[i])
}
}
console.log(evenNumbers) // => [0, 2, 4, 6, 8]
and:
// declarative
range(10).filter(v => v % 2 === 0) // => [0, 2, 4, 6, 8]

It seems you come from a Python or PHP background, but JavaScript does not have a global range()-function. See this post for an alternative.
Edit: A simple solution in this case would simply be to write:
let numbers = [0,1,2,3,4,5,6,7,8,9]
Sure, it's a bit verbose, but it's also very easy to read, and in a small case like this, it's not problematic.
If the purpose of the exercise was the difference between imperative and declarative programming, range(2) vs [0,1,2] should not matter.

Related

Performance cost of the for-of loop

Recently I was experimenting with ES6 code using babel. I was quite surprised to see the verbose code of a compiled for of loop. Here is an example:
ES6
const a = [1, 2, 3, 4, 5];
for (const i of a)
{
console.log(i);
}
Compiled
"use strict";
var a = [1, 2, 3, 4, 5];
for (
var _iterator = a,
_isArray = Array.isArray(_iterator),
_i = 0,
_iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();
;
) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var i = _ref;
console.log(i);
}
Whereas standard for loops, or a .forEach loop look almost exactly the same compiled as they do in ES6. I use the for of loop quite a lot in my code, it is a nice concise way to iterate over arrays. But until now I was unaware of all the added state and logic this brings with it. I would like to know whether using this compared to a normal for loop or .forEachhas a non-negligible performance cost?
I would like to know whether using this compared to a normal for loop or .forEach has a non-negligible performance cost?
That completely depends on the size of your array.
Unless you're iterating over millions of elements, you're not going to notice a difference.
Babel expands the loop this much for compatibility purposes. Older browsers don't have for...of, but the functionality can be reproduced like that.

A range function in Javascript written recursively

For my own learning and practice I tried to implement a function in Javascript which would populate an array with integers from 1 to the argument 'limit'.
One way I did it was with a for loop:
function getRange(limit) {
const range = [];
for (let i = 1; i <= limit; i++) {
range.push(i);
}
return range;
}
Then I wanted, again for my practice, to try and write it with a recursive function and came up with the following:
function recGetRange(limit, array) {
const range = array || [];
if (limit > 0) {
range.push(limit);
recGetRange(limit - 1, range);
}
return range.reverse();
}
Now both seem to work fine, but both seem also to fail when tried on large numbers. Yet the recursive option fails much earlier. I'm not exactly sure but the for loop seems to work for numbers 1E4 or 1E5 times larger at least.
Am I doing something wrong here with those implementations, or is it just a dead end even trying something like that?
Thanks!
A more "canonical" form of the recursion (with out passing arrays and the reversing) would be:
function range(limit) {
// end condition
if (limit <= 0) return [];
// main recursion
var l = range(limit-1);
l.push(limit);
return l;
}
This is almost the same as yours, but it has a more "commonly" used structure.
Tail recursion and TCO
Recursion is the functional equivalence of imperative loops with an additional stack structure.
In getRange you don't use an additional stack structure but merely a plain for loop. This is the reason why you can express getRange with tail recursion, where the recursive call is the last expression inside the body of the recursive function. Tail recursion shares a single call stack frame for the entire recursive iteration, i.e. stack overflows are no longer possible.
Unfortunately, Javascript engines don't support tail recursion optimization (TCO) yet. Hence the stack overflow. But they will support TCO eventually.
Here is a more general approach, which follows the functional paradigm. sequence is a higher order function that takes a stepper function to create the sequence recursively. The result is accumulated in an array (acc). Now you can produce sequences of every data type that has an ordering:
const sequence = stepper => (x, y) => {
const aux = (acc, z) => z <= y // inner auxiliary function
? aux(acc.concat(z), stepper(z)) // recursive case
: acc; // base case
return aux([], x);
};
const inc = x => x + 1;
const dbl = x => x * 2;
const succ = x => String.fromCharCode(x.charCodeAt(0) + 1);
console.log(sequence(inc) (1, 5)); // [1, 2, 3, 4, 5]
console.log(sequence(dbl) (2, 32)); // [2, 4, 8, 16, 32]
console.log(sequence(succ) ("c", "g")); // ["c", "d", "e", "f", "g"]
Generator functions
Generator functions are another means to create sequences. Please note that you don't need an accumulator anymore, because generator functions are stateful. To store the sequence you have to apply the function to a composite type that supports the Iterable protocol (like Array.from):
const sequence = stepper => (x, y) => {
function* aux() {
while (true) {
yield x;
x = stepper(x);
if (x > y) break;
}
}
return aux();
};
const sqr = x => x * x;
console.log(Array.from(sequence(sqr) (2, 256))); // [2, 4, 16, 256]

Writing a parameterless function in Ramda in a point free style?

Consider the working code below:
var randN = x => () => Math.floor(x*Math.random());
var rand10 = randN(10)
times(rand10, 10) // => [6, 3, 7, 0, 9, 1, 7, 2, 6, 0]
randN is a function that takes a number and returns an RNG that, when called, will return a random int in the range [0, N-1]. So it's a factory for specific RNGs.
I've been using ramda.js, and learning functional programming theory, and my question is: Is it possible to rewrite randN in a point free style using ramda?
For example, I could write:
var badAttempt = pipe(multiply(Math.random()), Math.floor)
This would satisfy the "point-free style" requirement, but fails to behave the same way as randN: calling badAttempt(10) simply returns a single random number between 1 and 10, rather than a function that generates a random number between 1 and 10 when called.
I have not been able to find a combination of ramda functions that enables me to do the rewrite in a point-free style. I can't tell if this is just a failure on my part, or something special about using random, which breaks referential transparency and therefore may be incompatible with a point free style.
update
my own slight variation on the solution, after discussing it with Denys:
randN = pipe(always, of, append(Math.random), useWith(pipe(multiply, Math.floor)), partial(__,[1,1]))
This would help with an extra function for abstracting a function to re-evaluate its arguments each time it is called.
thunk = fn => R.curryN(fn.length, (...args) => () => fn(...args))
The only purpose of this function would be to cause some side effect within the given fn function.
Once we have thunk function, we can define randN like so:
randN = thunk(R.pipe(S.S(R.multiply, Math.random), Math.floor))
R.times(randN(10), 5) // e.g. [1, 6, 9, 4, 5]
Note: S.S here is the S combinator from Sanctuary which does effectively the same thing as R.converge(multiply, [Math.random, identity]).
I do however only recommend going with a point-free solution if it actually improves the readability of a function.
I don't know if it's a good idea to learn functional programming using a specific library, because the characteristics of a lib and the functional paradigm will mix inevitably. In practice, however, Ramda is incredibly useful. It bridges the gap between the imperative reality and the functional Fantasy Land in Javascript :D
Here's a manual approach:
// a few generic, reusable functions:
const comp = f => g => x => f(g(x)); // mathematical function composition
const comp2 = comp(comp)(comp); // composes binary functions
const flip = f => x => y => f(y)(x); // flips arguments
const mul = y => x => x * y; // first class operator function
// the actual point-free function:
const randN = comp2(Math.floor)(flip(comp(mul)(Math.random)));
let rand10 = randN(10); // RNG
for (let i = 0; i < 10; i++) console.log(rand10());
It's worth mentioning that randN is impure, since random numbers are impure by definition.
var randN = R.converge(R.partial, [R.wrap(R.pipe(R.converge(R.multiply, [Math.random, R.identity]), Math.floor), R.identity), R.of])
var rand10 = randN(10)
alert(R.times(rand10, 10)) // => [3, 1, 7, 5, 7, 5, 8, 4, 7, 2]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.js"></script>

Filter in functional languages with original non-filtered elements?

I want to return an array that that maps some filtered elements - but I want to keep the non-filtered elements where they are.
i.e. Is there an easy way to do this?:
array
.filter(
function(element){
// some test
}
)
.map(
function(element){
// some mapping
}
)
The closest solution I've come up with is something along the lines of:
array
.map(
function(value, index){
if (<test>) {
return <mapping>(value);
}
}
)
but I feel this somewhat breaks the spirit of functional programming.
I'm not asking for a specific language implementation, although an example in Scala or JavaScript would be nice.
EDIT: Here's a concrete example of what I'm looking for:
[1,2,3,4,11,12]
Mapping all elements to element*10, for all elements in array which are greater than 10, should yield
[1,2,3,4,110,120]
EDIT2: I apologize for using the word "mutate." I did not mean mutate the original array - I was thinking more along the lines of mutating a copy of the array.
It's not really going to be functional if you're using a mutable collection. But you can use transform in Scala:
scala> val a = Array(1,2,3,4,11,12)
a: Array[Int] = Array(1, 2, 3, 4, 11, 12)
scala> a.transform {i => if(i > 10) i * 10 else i}
res10: scala.collection.mutable.WrappedArray[Int] = WrappedArray(1, 2, 3, 4, 110, 120)
edit:
If you want filter and map separated, use a view:
scala> a
res22: Array[Int] = Array(1, 2, 3, 4, 11, 12)
scala> a.view.filter(_ > 10).transform(_ * 10)
res23: scala.collection.mutable.IndexedSeqView[Int,Array[Int]] = SeqViewF(...)
scala> a
res24: Array[Int] = Array(1, 2, 3, 4, 110, 120)
Is collect what you are after?
scala> List(2, 3, 5, 6, 9).filter(_ < 5).map(_ * 100)
res30: List[Int] = List(200, 300)
scala> List(2, 3, 5, 6, 9).collect { case i if i < 5 => i * 100 }
res31: List[Int] = List(200, 300)
You could provide your filter and map function to a 'combining' function; I've tried an example on http://jsfiddle.net/xtofl/UDbyL/.
The idea is to apply the 'mapping' (which I would call inplace mapping) to all elements conforming to the filtering predicate in the original array.
Although these sorts of operations are possible in principle, the Scala library does not provide them.
You can build your own using indices (or views on indices):
scala> val a = Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> a.indices.view.filter(i=>a(i)%2==0).foreach(i=>a(i)=0)
scala> a
res1: Array[Int] = Array(1, 0, 3, 0, 5)
It's slightly awkward, but usually a little better than the if-statement version (in that at least you can see the filter and assignment steps separately).
Hej jiaweihli
the easiest solution is to reassign it to the reference ... ie mutating the reference
and not the data. This has some benefits if the reference is in other places you
are not mutating it under there noses.
EX:
x = x.filter(filterOpp);
ps! the second example there dosent work.
GL
The problem you are having is that you are thinking of filtering, and filtering is not what you want. If you don't want to remove elements, it is not a filter.
All you need is a simple map:
array.map(x => if(x > 10) x * 10 else x)
Or, if you think your conditions are too complex,
array.map {
case x if x > 10 => x * 10
case x => x
}
How about something like this: (psuedo javascript)
filteredMap = function(element) {
if(filterFunc(element)){
return mapFunc(element);
}
return element;
}
array = array.map(filteredMap)
Unless you explicitly are required to mutate the array (which isn't "functional") this should get you what you want.

Tersest way to create an array of integers from 1..20 in JavaScript

What would be the tersest way to create this array:
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
For example, a for loop:
var x = [];
for (var i=1;i<=20;i++) {
x.push(i);
}
Or a while loop:
var x = [], i = 1, endInt = 20;
while (i <= endInt) {
x.push(i);
i++;
}
Would there be other examples that would be terser -- in other words -- less code? I'm thinking of things like in Ruby where the equivalent code I believe would be as simple as 1..20. I'm not aware of syntax like that in JavaScript but I'm wondering if there are shorter ways to do that same thing.
UPDATE: I wasn't thinking of removing semicolons or var for answers in the question, but I have to admit the question implies that. I am more curious about algorithms than shaving bytes. Sorry if I was unclear! Also, making it into a function is simple enough, just slap function range(start, end) { /* guts here */ } around it and you're there. The question is are there novel approaches to the "guts."
Favorite method
Update Sep13,2015:
Just came up with this new method which works with browsers which support the ES6 standard:
> Array(5).fill().map((x,i)=>i)
[0, 1, 2, 3, 4]
Note the above does a tiny bit of extra work (fills with undefined) but is relatively minor vis-a-vis the speedup you can achieve by using a for loop, and if you forget the .fill you may be confused why your array is mysteriously [empty x 5]. You can encapsulate the above as a custom function, or alternatively use a somewhat more intended method:
> Array.from(Array(5),(x,i)=>i)
[0, 1, 2, 3, 4]
You can of course directly go from that into whatever you want to do, like python's list comprehensions e.g. [i**2 for i in range(5)]:
> Array.from(Array(5), (_,i)=> i**2)
[0, 1, 4, 9, 16]
... or if you want to get more complicated...:
> Array.from(Array(5), (_,i)=> {
const R = /*some computation*/;
return /*etc*/;
});
[edit May,2021]: theoretically tersest way of defining such a function nowadays is f=i=>i?[...f(i-1),i]:[], where you replace f with range1 or whatever the name is, but which would be very slow (quadratic complexity) due to intermediate structures so should never be used. f=i=>i?f(i-1)&&x.push(i)&&x:x=[] is linear complexity but relies on abuse of notation and is unreadable and pollutes global variables as well. But, since defining arrow functions (which don't bind but rather inherit this) is pretty terse nowadays, you could just wrap the above solution:
const range1 = n=> Array.from(Array(n), (_,i)=> i+i);
// range1(5)==[1, 2, 3, 4, 5]
Circumstantially, the tersest way to do a range(N), if you already have a list lying around of exactly that length N, is just to map it: e.g. rather than do Array.from(Array(myArr.length), (_,i)=> i**2), you would just do myArr.map((_,i)=> i**2). (This has no side-effect unless you want it to.)
everything below is historical:
After thinking about it a bit, this is the shortest implementation of the standard range(N) function in JavaScript I could come up with:
function range1(i){return i?range1(i-1).concat(i):[]}
Note: Do not use this in production; it's O(N^2)
Contrast with current top-voted answer:
function range1(i){var x=[];var i=1;while(x.push(i++)<i){};return x}
Example:
> range1(5)
[1, 2, 3, 4, 5]
This is like the poster child for recursion, though I was expecting it to be longer until I thought of ternary-if-statement, which brings it down to 42 necessary characters.
Note that the "standard" range function returning [start,end) can be written by doing .concat(i-1).
Update: Ooh, I discovered an incredibly short version with ugly imperative syntax by abusing for loops, reverse-ordering, the fact that assignments return a value: for(y=[],i=20;y[--i]=i;){} consisting of only 25 characters (though you will want var y which you can insert into a for loop, and +1 if you don't want 0...19). While it is not shorter if you need to define a function, it is shorter than i?r(i-1).concat(i):[] if you do not need to make a function.
Added some performance profiling testcases: it seems that everything besides a standard in-order for-loop is 10x slower, at least on V8. https://jsperf.com/array-range-in-javascript
(Of course, none of this matters if you're programming in a functional style anyway and would hit every element with a function call anyway.)
It can be done with features from the ES6, currently only supported by Firefox thou. I found a compatibility table here: http://kangax.github.io/compat-table/es6/
Array.from(new Array(20), (x,i) => i+1)
If you want to have some other range then I guess you could do
Array.from(new Array(5), (x,i) => i+5)
Which would then be [5,6,7,8,9]
You can do this with a while loop where the push happens inside the condition.Array.push returns the length of the array, which happens to be the same as the value in this case. So, you can do the following:
x = []; //normally would use var here
i = 1; //normally would use var here
while(x.push(i++)<20){}
//at this point, x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Condensed version (31 characters)
x=[];i=1;while(x.push(i++)<20);
jsFiddle example
while-- is the way to go
var a=[],b=10;while(b--)a[b]=b+1
returns [1,2,3,4,5,6,7,8,9,10]
explained with start & length
var array=[],length=20,start=5;while(length--)array[length]=length+start
returns [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
want range?
explained with start & end
var array=[],end=30,start=25,a=end-start+1;while(a--)array[a]=end--
returns [25, 26, 27, 28, 29, 30]
for --
for(var a=[],b=20;b>0;b--,a[b]=b+1)
for++
for(var a=[],b=0;b<20;b++,a[b]=b+1)
WHY is this theway to go?
while -- is prolly the fastest loop;
direct setting is faster than push & concat;
[] is also faster than new Array(10);
it's not much longer code than all the others
byte saving techniques:
use the arguments as a placholder forthe in function variables
don't use new Array(),push(),concat() if not needed
place "(){};," only when needed.
use a,b,c,d... in short functions.
so if u want a function for this
with start,end (range)
function range(a,b,c,d){d=[];c=b-a+1;while(c--)d[c]=b--;return d}
so now range(3,7) returns [3,4,5,6,7]
u save bytes in many ways here and this function is also very fast as it does not use concat, push, new Array and it's made with a while --
If you're OK with 0-20, here are my latest favs from recent code golfing:
[...'0'.repeat(21)].map((_,i)=>i)
Array.from({length:21},(_,i)=>i)
Array(21).fill().map((_,i)=>i)
[...Array(21)].map((_,i)=>i)
Array(21).map((_,i)=>i)
[...Array(21).keys()]
Using ES6
numArr = Array(5).fill(0).reduce(arr=>{ arr.push(arr.length); return arr },[])
if you accept to have a counter starting from 0 instead of 1...
const zeroNineteen = [...Array(20).keys()];
// outputs [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
if you really need it to start with 1:
const terserst = [...Array(21).keys()].slice(1);
it's 30 characters and yet readable, don't you think?
I can't think of a way with less characters than ~46:
var a=[];while(a.length<20)a.push(a.length+1);
Granted, you could make a function out of that.
Reading your comments about a function, you could do something like
var range = function (start, end) {
var arr = [];
while (start <= end) {
arr.push(start++)
}
return arr;
};
Then range(1, 20) would return the array as expected.
I suppose this is the shortest way:
var i=0, arr = [];
while (i++<20){
arr.push(i);
}
or associating on the 'perverse' code in EndangeredMassa's answer:
var i,arr; while (i=i||1, (arr=arr||[]).push(i++)<20){}
You could always create a function...
function createNumArray(a, b) {
var arr = [],
i = a;
while((arr[arr.length] = i) < b) {i++}
return arr;
}
Which allows you to write succinct code later on such as...
var arr = createNumArray(1, 20);
If you are looking to shave characters off anyway possible without regard for readability, this is the best I can do:
var x=[],i=0
while(i<20)
x[i]=i+++1
Not a lot better than yours though.
Edit:
Actually this works better and shaves off a couple characters:
var x=[],i=0
while(i<20)
x[i]=++i
Edit 2:
And here's my entry for a general "range" function in the least number of characters:
function range(s,e){var x=[];while(s<e+1)x.push(s++);return x}
Again, don't write code this way. :)
Array.from({length: n}).map((_, i) => i);
In my knowledge, the option of using for loop, as you mentioned, is the most tersest.
That is,
var x = [];
for (var i=1;i<=20;i++) {
x.push(i);
}
var i = 0;
var x = [];
while (i++ < 20) x.push(i);
JSFiddle
I'd extend Array's prototype to make it simple to access:
Array.prototype.range = function(start, end) {
if (!this.length) {
while (end >= start) {
this.push(start++);
}
} else {
throw "You can only call 'range' on an empty array";
}
return this;
};
var array = [].range(1, 20);
While the above is the nearest I can think of with respect to the syntactic sugar you're looking for, you may want to try out CoffeeScript.
It supports the notation you're after.
CoffeeScript:
test = [1..20]
alert test
Renders to JavaScript:
var test;
test = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
alert(test);
You can try out live examples on their site, and see the conversion it does as you type.
Just click the TRY COFFEESCRIPT link at the top, and you'll get a console where you can test some code.
There's always the IterableInt:
for (const z of new IterableInt(15)) {
// 15,14,13....3,2,1
}
implemented like so:
class IterableInt {
constructor(val) {
if (val < 0) {
throw new Error('cannot iterate over a negative number.')
}
this.val = val;
}
static create(val){
return new IterableInt(val);
}
[Symbol.iterator]() {
const self = this;
return {
next() {
const value = self.val--;
const done = value <= 0;
return {value, done}
}
}
}
}
to do things like:
for (const z of new IterableInt(3,15)) {
// 3,4,5...14,15
}
go to this gist:
https://gist.github.com/ORESoftware/1aca4ae704b355c45702d11c0e245776

Categories

Resources