Is there a way in Javascript to write something like this easily:
[1,2,3].times do {
something();
}
Any library that might support some similar syntax maybe?
Update: to clarify - I would like something() to be called 1,2 and 3 times respectively for each array element iteration
Just use a for loop:
var times = 10;
for(var i = 0; i < times; i++){
doSomething();
}
Possible ES6 alternative.
Array.from(Array(3)).forEach((x, i) => {
something();
});
And, if you want it "to be called 1,2 and 3 times respectively".
Array.from(Array(3)).forEach((x, i) => {
Array.from(Array(i+1)).forEach((x, i2) => {
console.log(`Something ${ i } ${ i2 }`)
});
});
Update:
Taken from filling-arrays-with-undefined
This seems to be a more optimised way of creating the initial array, I've also updated this to use the second parameter map function suggested by #felix-eve.
Array.from({ length: 3 }, (x, i) => {
something();
});
The easiest way is by destructuring the Array,
which automatically sets undefined for each item, if the item's value was not set:
[...Array(5)].map((item, i) => console.log(item, i))
The keys Array method can also be used to generate an Array of indices values:
[...Array(3).keys()] // [0, 1, 2]
Alternatively, create an Array and fill all items with undefined before using map:
👉 Read detailed reason why map is skipping never-defined array items
⚠️ Array.fill has no IE support
Array(5).fill().map((item, i) => console.log(item, i))
If you want to make the above more "declarative", my currently opinion-based solution would be:
const iterate = times => callback => [...Array(times)].map((n,i) => callback(i))
iterate(3)(console.log)
Using old-school (reverse) loop:
// run 5 times:
for( let i=5; i--; )
console.log(i)
Or as a declarative "while":
const run = (cb, ...args) => count => { while(count--) cb(...args) }
// executes the callback with whatever arguments, 3 times
run(console.log, 1,2,3)(3)
This answer is based on Array.forEach, without any library, just native vanilla.
To basically call something() 3 times, use:
[1,2,3].forEach(function(i) {
something();
});
considering the following function:
function something(){ console.log('something') }
The output will be:
something
something
something
To complete this questions, here's a way to do call something() 1, 2 and 3 times respectively:
It's 2017, you may use ES6:
[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => {
something()
}))
or in good old ES5:
[1,2,3].forEach(function(i) {
Array(i).fill(i).forEach(function() {
something()
})
}))
In both cases, the output will be
The output will be:
something
something
something
something
something
something
(once, then twice, then 3 times)
With lodash:
_.each([1, 2, 3], (item) => {
doSomeThing(item);
});
//Or:
_.each([1, 2, 3], doSomeThing);
Or if you want to do something N times:
const N = 10;
_.times(N, () => {
doSomeThing();
});
//Or shorter:
_.times(N, doSomeThing);
Since you mention Underscore:
Assuming f is the function you want to call:
_.each([1,2,3], function (n) { _.times(n, f) });
will do the trick. For example, with f = function (x) { console.log(x); }, you will get on your console:
0 0 1 0 1 2
You can also do the same thing with destructuring as follows
[...Array(3)].forEach( _ => console.log('do something'));
or if you need index
[...Array(3)].forEach(( _, index) => console.log('do something'));
How about a simple while.
let times = 5;
while (times--) {
console.log(times+1)
}
References on how this works: Falsy and Decrement (--)
Edit: If there's a possibility for times to be manipulated elsewhere, it's safer to use times-- > 0 instead of times-- to prevent an infinite loop if the times drops below 0
If you can't use Underscorejs, you can implement it yourself. By attaching new methods to the Number and String prototypes, you could do it like this (using ES6 arrow functions):
// With String
"5".times( (i) => console.log("number "+i) );
// With number variable
var five = 5;
five.times( (i) => console.log("number "+i) );
// With number literal (parentheses required)
(5).times( (i) => console.log("number "+i) );
You simply have to create a function expression (of whatever name) and assign it to whatever property name (on the prototypes) you would like to access it as:
var timesFunction = function(callback) {
if (typeof callback !== "function" ) {
throw new TypeError("Callback is not a function");
} else if( isNaN(parseInt(Number(this.valueOf()))) ) {
throw new TypeError("Object is not a valid number");
}
for (var i = 0; i < Number(this.valueOf()); i++) {
callback(i);
}
};
String.prototype.times = timesFunction;
Number.prototype.times = timesFunction;
Array.from (ES6)
function doSomthing() {
...
}
Use it like so:
Array.from(Array(length).keys()).forEach(doSomthing);
Or
Array.from({ length }, (v, i) => i).forEach(doSomthing);
Or
// array start counting from 1
Array.from({ length }, (v, i) => ++i).forEach(doSomthing);
Just use a nested loop (maybe enclosed in a function)
function times( fct, times ) {
for( var i=0; i<times.length; ++i ) {
for( var j=0; j<times[i]; ++j ) {
fct();
}
}
}
Then just call it like this:
times( doSomething, [1,2,3] );
times = function () {
var length = arguments.length;
for (var i = 0; i < length ; i++) {
for (var j = 0; j < arguments[i]; j++) {
dosomthing();
}
}
}
You can call it like this:
times(3,4);
times(1,2,3,4);
times(1,3,5,7,9);
const loop (fn, times) => {
if (!times) { return }
fn()
loop(fn, times - 1)
}
loop(something, 3)
There is a fantastic library called Ramda, which is similar to Underscore and Lodash, but is more powerful.
const R = require('ramda');
R.call(R.times(() => {
console.log('do something')
}), 5);
Ramda contains plenty of useful functions. See Ramda documentation
you can use
Array.forEach
example:
function logArrayElements(element, index, array) {
console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements)
or with jQuery
$.each([52, 97], function(index, value) {
alert(index + ': ' + value);
});
http://api.jquery.com/jQuery.each/
// calls doSomething 42 times
Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );
and
// creates 42 somethings
var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );
or ( via https://stackoverflow.com/a/20066663/275501 )
Array.apply(null, {length: 42}).forEach( doSomething );
var times = [1,2,3];
for(var i = 0; i < times.length; i++) {
for(var j = 0; j < times[i];j++) {
// do something
}
}
Using jQuery .each()
$([1,2,3]).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
OR
var x = [1,2,3];
$(x).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
EDIT
You can do like below with pure JS:
var times = [1,2,3];
times.forEach(function(i) {
// do something
});
These answers are all good and well and IMO #Andreas is the best, but many times in JS we have to do things asynchronously, in that case, async has you covered:
http://caolan.github.io/async/docs.html#times
const async = require('async');
async.times(5, function(n, next) {
createUser(n, function(err, user) {
next(err, user);
});
}, function(err, users) {
// we should now have 5 users
});
These 'times' features arent very useful for most application code, but should be useful for testing.
Assuming we can use some ES6 syntax like the spread operator, we'll want to do something as many times as the sum of all numbers in the collection.
In this case if times is equal to [1,2,3], the total number of times will be 6, i.e. 1+2+3.
/**
* #param {number[]} times
* #param {cb} function
*/
function doTimes(times, cb) {
// Get the sum of all the times
const totalTimes = times.reduce((acc, time) => acc + time);
// Call the callback as many times as the sum
[...Array(totalTimes)].map(cb);
}
doTimes([1,2,3], () => console.log('something'));
// => Prints 'something' 6 times
This post should be helpful if the logic behind constructing and spreading an array isn't apparent.
Given a function something:
function something() { console.log("did something") }
And a new method times added to the Array prototype:
Array.prototype.times = function(f){
for(v of this)
for(var _ of Array(v))
f();
}
This code:
[1,2,3].times(something)
Outputs this:
did something
did something
did something
did something
did something
did something
Which I think answers your updated question (5 years later) but I wonder how useful it is to have this work on an array? Wouldn't the effect be the same as calling [6].times(something), which in turn could be written as:
for(_ of Array(6)) something();
(although the use of _ as a junk variable will probably clobber lodash or underscore if you're using it)
Using Array.from and .forEach.
let length = 5;
Array.from({length}).forEach((v, i) => {
console.log(`#${i}`);
});
TypeScript Implementation:
For those of you who are interested in how to implement String.times and Number.times in a way that is type safe and works with the thisArg, here ya go:
declare global {
interface Number {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
interface String {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
}
Number.prototype.times = function (callbackFn, thisArg) {
const num = this.valueOf()
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
if (isNaN(num)) {
throw new RangeError('Must not be NaN')
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
String.prototype.times = function (callbackFn, thisArg) {
let num = parseInt(this.valueOf())
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
// num is NaN if `this` is an empty string
if (isNaN(num)) {
num = 0
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
A link to the TypeScript Playground with some examples can be found here
This post implements solutions posted by: Andreas Bergström, vinyll, Ozay Duman, & SeregPie
Just thought I'd add, there is a nifty JS method called .repeat(n) which will repeat a string 'n' number of times. So if you're looking for something to repeat a string 'n' number of times...
function repeatString (number, string) {
return string.repeat(number);
}
So if you did...
repeatString(3, 'Hey there! ');
You'd get: 'Hey there! Hey there! Hey there! '
Related
I am working with an object where I need to preserve the order of the entries, even though some keys are alphanumeric and others are integers. (Yes, I know.)
The object I'm starting with looks like this:
{
a: 'the',
quick: 'quick',
b: 'brown',
fox: 'fox'
}
After manipulation, the object should look like this:
{
a: 'the',
0: 'quick',
b: 'brown',
1: 'fox'
}
But. Because iteration order in javascript objects differs from insertion order (integers are iterated first), if I go about this straightforwardly, I won't get the correctly ordered result:
let myReindexedObject = {};
myReindexedObject['a'] = 'the';
myReindexedObject['0'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1'] = 'fox';
console.log(myReindexedObject);
I've tried to solve this issue by building a Map (which, unlike an object, preserves entry order) which I can then convert into an object.
Source: (I adapted this gist by Luke Horvat: Convert ES6 Map to Object Literal .)
Can you guess what happens?
let myMap = new Map();
myMap.set('a', 'the');
myMap.set('0', 'quick');
myMap.set('b', 'brown');
myMap.set('1', 'fox');
let myArray = Array.from(myMap);
let myReindexedObject = myArray.reduce((myReindexingObject, [key, value]) => {
return Object.assign(myReindexingObject, { [key]: value })
}, {});
console.log(myReindexedObject);
Is there any way I can use integer-based keys like 0 and 1 and still preserve the object entries in a custom order?
Or do I need to consider other approaches?
In the process of writing the question above, it suddenly occurred to me as I was typing:
(integers are iterated first)
that what a javascript engine recognises as an integer and what humans recognise as a number are, of course, not the same.
To any human, these two:
1
1.
are not typographically identical, but they are pretty much equivalent.
To any javascript interpreter, they are entirely distinct: the first is an integer; the second is not.
Working Example:
let myReindexedObject = {};
myReindexedObject['a'] = 'the';
myReindexedObject['0.'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1.'] = 'fox';
console.log(myReindexedObject);
If the javascript interpreter needs to identify these indexes, it can do so, using the regex:
/d+\./
and, once identified, if it needs to know the integer that the string corresponds to, it can use:
parseInt(myIndex);
I will use this approach for now.
If anyone can suggest a better approach, I will be happy to upvote and accept.
We can define our own object, that keeps track of properties. And by intercepting required features we can make it work.
Using Proxy it's easily achievable:
// DEMO
let o = new CoolObject();
o['a'] = 'the';
o['0'] = 'quick';
o['b'] = 'brown';
o['1'] = 'fox';
o['c'] = 'jumped';
delete o['c'];
console.log('Object.keys: ', Object.keys(o));
console.log('JSON.stringify: ', JSON.stringify(o));
console.log('console.log: ', o);
console.log('Object.getOwnPropertyNames: ', Object.getOwnPropertyNames(o));
console.log('obj.propertyIsEnumerable("keys"): ', o.propertyIsEnumerable('keys'));
console.log('obj.propertyIsEnumerable("a"): ', o.propertyIsEnumerable('a'));
<script src="https://cdn.jsdelivr.net/gh/OnkarRuikar/temp#main/CoolObject.js"></script>
See console logs for output.
Note the insertion ordered property names. Result of getOwnPropertyNames are also insertion ordered except methods.
The CoolObject class definition:
(function () {
// original functions
let _keys = Object.keys;
let _getOwnPropertyNames = Object.getOwnPropertyNames;
let _defineProperty = Object.defineProperty;
let _stringify = JSON.stringify;
let _log = console.log;
// main feature definition
let CoolObject = function () {
let self = this;
let handler = {
_coolKeys: [],
set(target, key, val) {
let keys = this._coolKeys;
if (!keys.some(k => k === key))
keys.push(key);
target[key] = val;
},
get(target, key) {
return target[key];
},
keys() {
return this._coolKeys.slice(0);
},
deleteProperty(target, key) {
let keys = this._coolKeys;
const index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
delete target[key];
},
defineProperty(obj, prop, val) {
let keys = this._coolKeys;
if (!keys.some(k => k === prop))
keys.push(prop);
_defineProperty(self, prop, val);
},
getOwnPropertyNames(obj) {
let props = _getOwnPropertyNames(obj);
return [...new Set([...this._coolKeys, ...props])];
},
// many improvements can be done here
// you can use your own modified pollyfill
stringifyHelper(obj, replacer, space) {
let out = '{';
for (let key of this._coolKeys) {
out += `"${key}":${_stringify(obj[key], replacer, space)}, `;
}
out += '}';
return out;
},
};
_defineProperty(self, 'keys', { value: () => handler.keys() });
_defineProperty(self, 'getOwnPropertyNames', { value: (o) => handler.getOwnPropertyNames(o) });
_defineProperty(self, 'stringify', { value: (...args) => handler.stringifyHelper(...args) });
return new Proxy(self, handler);
} // CoolObject end
// ----- wrap inbuilt objects -----
Object.keys = function (obj) {
if (!(obj instanceof CoolObject))
return _keys(obj);
return obj.keys();
}
Object.defineProperty = function (obj, prop, val) {
if (!(obj instanceof CoolObject))
_defineProperty(...arguments);
obj.defineProperty(...arguments);
}
Object.getOwnPropertyNames = function (obj) {
if (!(obj instanceof CoolObject))
return _getOwnPropertyNames(obj);
return obj.getOwnPropertyNames(obj);
}
JSON.stringify = function (obj, replacer, indent) {
if (!(obj instanceof CoolObject))
return _stringify(...arguments);
return obj.stringify(...arguments);
}
console.log = function () {
let myArgs = [];
for (let arg of arguments) {
if (arg instanceof CoolObject) {
let keys = arg.keys();
arg = Object.assign({}, arg);
for (let key of keys) {
arg[`.${key}`] = arg[key]
delete arg[key];
}
}
myArgs.push(arg);
}
_log(...myArgs);
}
window.CoolObject = CoolObject;
})();
The handler object maintains property names in _coolKeys array. And tracks addition and deletion operations. To make object behave like an original Object we need to wrap some inbuilt APIs, like Object.keys().
Note: for the demo I've implemented bare minimum rough code. Many improvements can be done. You can intercept more inbuilt APIs as per your requirements.
What is the principle behind this?
newArr.some(Array.isArray) === newArr.some(elem => Array.isArray(elem))
How is posible that they are parsed as equal?
I thought that newArr.some(Array.isArray) === newArr.some(Array.isArray()) (assuming that some is a loop and that JS assumed each val as the implicit arg of the func), but it's not. So, I'm confused. Please, help me.
Here, there are 2 applications of the cases above:
function flatMultiArr(arr) {
let newArr = [].concat(...arr);
return newArr.some(Array.isArray)
? flatMultiArr(newArr)
: newArr
}
console.log();//[ 1, {}, 3, 4 ]
function flatMultiArr(arr) {
let newArr = [].concat(...arr);
return newArr.some(elem => Array.isArray(elem))
? flatMultiArr(newArr)
: newArr
}
console.log();//[ 1, {}, 3, 4 ]
Note this question is not about how to flatten multidimentional arrays.
This principle is known as eta conversion. No, they are not "parsed as equal", they are different functions, but they behave the same, and therefore can be reasoned about equally. To simplify:
const f = Array.isArray
and
function f(x) { return Array.isArray(x); }
will have the same results when called1, i.e. f([]) or f(5).
1: In general, there are minor differences wrt to the this binding in the method and the number of arguments, but it works for Array.isArray.
Please note that callbacks are just functions. It is called eta-abstraction and makes your function slightly more lazy:
const fix = f => f(fix( f));
const fix_ = f => x => f(fix_(f)) (x);
// ^^^^ ^^^ eta abstraction
try {
const map = fix(go => f => ([x, ...xs]) =>
x == undefined
? []
: go(f) (xs).concat(f(x)));
}
catch (e) {
console.log(e.message);
}
const map_ = fix_(go => f => ([x, ...xs]) =>
x === undefined
? []
: [f(x)].concat(go(f) (xs)));
console.log(
map_(x => x * x) ([1,2,3]));
I trying to make next with closure:
function func(number) {
var result = number;
var res = function(num) {
return result + num;
};
return res;
}
var result = func(2)(3)(4)(5)(3);
console.log(result); // 17
I need to receive 2 + 3 + 4 + 5 + 3 = 17
But I got an error: Uncaught TypeError: number is not a function
You somehow have to signalize the end of the chain, where you are going to return the result number instead of another function. You have the choice:
make it return a function for a fixed number of times - this is the only way to use the syntax like you have it, but it's boring. Look at #PaulS' answer for that. You might make the first invocation (func(n)) provide the number for how many arguments sum is curried.
return the result under certain circumstances, like when the function is called with no arguments (#PaulS' second implementation) or with a special value (null in #AmoghTalpallikar's answer).
create a method on the function object that returns the value. valueOf() is suited well because it will be invoked when the function is casted to a primitive value. See it in action:
function func(x) {
function ret(y) {
return func(x+y);
}
ret.valueOf = function() {
return x;
};
return ret;
}
func(2) // Function
func(2).valueOf() // 2
func(2)(3) // Function
func(2)(3).valueOf() // 5
func(2)(3)(4)(5)(3) // Function
func(2)(3)(4)(5)(3)+0 // 17
You're misusing your functions.
func(2) returns the res function.
Calling that function with (3) returns the number 5 (via return result + num).
5 is not a function, so (4) gives an error.
Well, the (2)(3) part is correct. Calling func(2) is going to return you res, which is a function. But then, calling (3) is going to return you the result of res, which is a number. So the problem comes when you try to call (4).
For what you're trying to do, I don't see how Javascript would predict that you're at the end of the chain, and decide to return a number instead of a function. Maybe you could somehow return a function that has a "result" property using object properties, but mostly I'm just curious about why you're trying to do things this way. Obviously, for your specific example, the easiest way would just be adding the numbers together, but I'm guessing you're going a bit further with something.
If you want to keep invoking it, you need to keep returning a function until you want your answer. e.g. for 5 invocations
function func(number) {
var result = number,
iteration = 0,
fn = function (num) {
result += num;
if (++iteration < 4) return fn;
return result;
};
return fn;
}
func(2)(3)(4)(5)(3); // 17
You could also do something for more lengths that works like this
function func(number) {
var result = number,
fn = function () {
var i;
for (i = 0; i < arguments.length; ++i)
result += arguments[i];
if (i !== 0) return fn;
return result;
};
return fn;
}
func(2)(3, 4, 5)(3)(); // 17
I flagged this as a duplicate, but since this alternative is also missing from that question I'll add it here. If I understand correctly why you would think this is interesting (having an arbitrary function that is applied sequentially to a list of values, accumulating the result), you should also look into reduce:
function sum(a, b) {
return a + b;
}
a = [2, 3, 4, 5, 3];
b = a.reduce(sum);
Another solution could be just calling the function without params in order to get the result but if you call it with params it adds to the sum.
function add() {
var sum = 0;
var closure = function() {
sum = Array.prototype.slice.call(arguments).reduce(function(total, num) {
return total + num;
}, sum);
return arguments.length ? closure : sum;
};
return closure.apply(null, arguments);
}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); // function(){}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;
We can make light work of it using a couple helper functions identity and sumk.
sumk uses a continuation to keep a stack of the pending add computations and unwinds the stack with 0 whenever the first () is called.
const identity = x => x
const sumk = (x,k) =>
x === undefined ? k(0) : y => sumk(y, next => k(x + next))
const sum = x => sumk(x, identity)
console.log(sum()) // 0
console.log(sum(1)()) // 1
console.log(sum(1)(2)()) // 3
console.log(sum(1)(2)(3)()) // 6
console.log(sum(1)(2)(3)(4)()) // 10
console.log(sum(1)(2)(3)(4)(5)()) // 15
Do you have any real-world example of the use of the second and third parameters for the callback to Array.prototype.some or Array.prototype.any?
According to MDN:
callback is invoked with three arguments: the value of the element, the index of the
element, and the Array object being traversed.
I've personally never used them.
I have been working for some time on the Javascript functional programming library, Ramda, and early on we made the controversial decision not to use the index and array parameters for other similar functions that we created. There are good reasons for this, which I don't need to get into here, except to say that for some functions, such as map and filter, we find such extra parameters do have some occasional utility. So we offer a second function which supplies them to your callback. (For example, map.idx(yourFunc, list).)
But I've never even considered doing so for some or every. I never imagined a practical use of these. But there is now a suggestion that we include these functions in our list of index-supporting ones.
So my question again is whether you have ever found an actual, live, real-world callback function to some or every which actually needs these parameters? If so, could you describe it?
Answers of "No, I never do," would be helpful data too, thanks.
Quick search in our code:
function isAscending(array) {
return array.every(function (e, idx, arr) {
return (idx === 0) ? true : arr[idx-1] <= e;
});
}
I could imagine something like the following code to check whether an array is duplicate-free:
….every(function(v, i, arr) {
return arr.indexOf(v, i+1) == -1;
})
Where … is a complex expression so that you'd really have to use the arr parameter - which is no more an issue if you'd properly factor out the functionality in an own function that takes the array as an argument.
The second parameter can be useful sometimes, but I support your position that it is rather seldom used.
Yes, they are helpful
These extra parameters actually do come in handy, but not that often.
In the recent past, I had written a function to find all the permutations of a list of elements:
permute :: [a] -> [[a]]
For example permute [1,2,3] would be:
[ [1,2,3]
, [1,3,2]
, [2,1,3]
, [2,3,1]
, [3,1,2]
, [3,2,1]
]
The implementation of this function is quite simple:
If the input is [] then return [[]]. This is the edge case.
If the input is say [1,2,3]:
Add 1 to every permutation of [2,3].
Add 2 to every permutation of [1,3].
Add 3 to every permutation of [1,2].
Of course, the function is recursive. In JavaScript, I implemented it as follows:
var permute = (function () {
return permute;
function permute(list) {
if (list.length === 0) return [[]]; // edge case
else return list.reduce(permutate, []); // list of permutations
// is initially empty
}
function permutate(permutations, item, index, list) {
var before = list.slice(0, index); // all the items before "item"
var after = list.slice(index + 1); // all the items after "item"
var rest = before.concat(after); // all the items beside "item"
var perms = permute(rest); // permutations of rest
// add item to the beginning of each permutation
// the second argument of "map" is the "context"
// (i.e. the "this" parameter of the callback)
var newPerms = perms.map(concat, [item]);
return permutations.concat(newPerms); // update the list of permutations
}
function concat(list) {
return this.concat(list);
}
}());
As you can see, I have used both the index and the list parameters of the permutate function. So, yes there are cases where these extra parameters are indeed helpful.
However, they are also problematic
However these superfluous arguments can sometimes be problematic and difficult to debug. The most common example of this problematic behavior is when map and parseInt are used together: javascript - Array#map and parseInt
alert(["1","2","3"].map(parseInt));
As you can see it produces the unexpected output [1,NaN,NaN]. The reason this happens it because the map function calls parseInt with 3 arguments (item, index and array):
parseInt("1", 0, ["1","2","3"]) // 1
parseInt("2", 1, ["1","2","3"]) // NaN
parseInt("3", 2, ["1","2","3"]) // NaN
However, the parseInt function takes 2 arguments (string and radix):
First case, radix is 0 which is false. Hence default radix 10 is taken, resulting in 1.
Second case, radix is 1. There is no base 1 numeral system. Hence we get NaN.
Third case, radix is 2 which is valid. However there's no 3 in base 2. Hence we get NaN.
As you see, superfluous arguments can cause a lot of problems which are difficult to debug.
But, there is an alternative
So these extra arguments are helpful but they can cause a lot of problems. Fortunately, there is an easy solution to this problem.
In Haskell if you want to map over a list of values and the indices of each value then you use do it as follows:
map f (zip list [0..])
list :: [Foo]
[0..] :: [Int]
zip list [0..] :: [(Foo, Int)]
f :: (Foo, Int) -> Bar
map f (zip list [0..]) :: [Bar]
You could do the same thing in JavaScript as follows:
function Maybe() {}
var Nothing = new Maybe;
Just.prototype = new Maybe;
function Just(a) {
this.fromJust = a;
}
function iterator(f, xs) {
var index = 0, length = xs.length;
return function () {
if (index < length) {
var x = xs[index];
var a = f(x, index++, xs);
return new Just(a);
} else return Nothing;
};
}
We use a different map function:
function map(f, a) {
var b = [];
if (typeof a === "function") { // iterator
for (var x = a(); x !== Nothing; x = a()) {
var y = f(x.fromJust);
b.push(y);
}
} else { // array
for (var i = 0, l = a.length; i < l; i++) {
var y = f(a[i]);
b.push(y);
}
}
return x;
}
Finally:
function decorateIndices(array) {
return iterator(function (item, index, array) {
return [item, index];
}, array);
}
var xs = [1,2,3];
var ys = map(function (a) {
var item = a[0];
var index = a[1];
return item + index;
}, decorateIndices(xs));
alert(ys); // 1,3,5
Similarly you can create decorateArray and decorateIndicesArray functions:
function decorateArray(array) {
return iterator(function (item, index, array) {
return [item, array];
}, array);
}
function decorateIndicesArray(array) {
return iterator(function (item, index, array) {
return [item, index, array];
}, array);
}
Currently in Ramda you have two separate functions map and map.idx. The above solution allows you to replace map.idx with idx such that:
var idx = decorateIndices;
var arr = decorateArray;
var idxArr = decorateIndicesArray;
map.idx(f, list) === map(f, idx(list))
This will allow you to get rid of a whole bunch of .idx functions, and variants.
To curry or not to curry
There is still one small problem to solve. This looks ugly:
var ys = map(function (a) {
var item = a[0];
var index = a[1];
return item + index;
}, decorateIndices(xs));
It would be nicer to be able to write it like this instead:
var ys = map(function (item, index) {
return item + index;
}, decorateIndices(xs));
However we removed superfluous arguments because they caused problems. Why should we add them back in? Two reasons:
It looks cleaner.
Sometimes you have a function written by somebody else which expects these extra arguments.
In Haskell you can use the uncurry function to solve this problem:
map (uncurry f) (zip list [0..])
list :: [Foo]
[0..] :: [Int]
zip list [0..] :: [(Foo, Int)]
f :: Foo -> Int -> Bar
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f :: (Foo, Int) -> Bar
map (uncurry f) (zip list [0..]) :: [Bar]
In JavaScript the uncurry function is simply apply. It is implemented as follows:
function uncurry(f, context) {
if (arguments.length < 2) context = null;
return function (args) {
return f.apply(context, args);
};
}
Using uncurry we can write the above example as:
var ys = map(uncurry(function (item, index) {
return item + index;
}), decorateIndices(xs));
This code is awesome because:
Each function does only one job. Functions can be combined to do more complex work.
Everything is explicit, which is a good thing according to the Zen of Python.
There's no redundancy. There's only one map function, etc.
So I really hope this answer helps.
I trying to make next with closure:
function func(number) {
var result = number;
var res = function(num) {
return result + num;
};
return res;
}
var result = func(2)(3)(4)(5)(3);
console.log(result); // 17
I need to receive 2 + 3 + 4 + 5 + 3 = 17
But I got an error: Uncaught TypeError: number is not a function
You somehow have to signalize the end of the chain, where you are going to return the result number instead of another function. You have the choice:
make it return a function for a fixed number of times - this is the only way to use the syntax like you have it, but it's boring. Look at #PaulS' answer for that. You might make the first invocation (func(n)) provide the number for how many arguments sum is curried.
return the result under certain circumstances, like when the function is called with no arguments (#PaulS' second implementation) or with a special value (null in #AmoghTalpallikar's answer).
create a method on the function object that returns the value. valueOf() is suited well because it will be invoked when the function is casted to a primitive value. See it in action:
function func(x) {
function ret(y) {
return func(x+y);
}
ret.valueOf = function() {
return x;
};
return ret;
}
func(2) // Function
func(2).valueOf() // 2
func(2)(3) // Function
func(2)(3).valueOf() // 5
func(2)(3)(4)(5)(3) // Function
func(2)(3)(4)(5)(3)+0 // 17
You're misusing your functions.
func(2) returns the res function.
Calling that function with (3) returns the number 5 (via return result + num).
5 is not a function, so (4) gives an error.
Well, the (2)(3) part is correct. Calling func(2) is going to return you res, which is a function. But then, calling (3) is going to return you the result of res, which is a number. So the problem comes when you try to call (4).
For what you're trying to do, I don't see how Javascript would predict that you're at the end of the chain, and decide to return a number instead of a function. Maybe you could somehow return a function that has a "result" property using object properties, but mostly I'm just curious about why you're trying to do things this way. Obviously, for your specific example, the easiest way would just be adding the numbers together, but I'm guessing you're going a bit further with something.
If you want to keep invoking it, you need to keep returning a function until you want your answer. e.g. for 5 invocations
function func(number) {
var result = number,
iteration = 0,
fn = function (num) {
result += num;
if (++iteration < 4) return fn;
return result;
};
return fn;
}
func(2)(3)(4)(5)(3); // 17
You could also do something for more lengths that works like this
function func(number) {
var result = number,
fn = function () {
var i;
for (i = 0; i < arguments.length; ++i)
result += arguments[i];
if (i !== 0) return fn;
return result;
};
return fn;
}
func(2)(3, 4, 5)(3)(); // 17
I flagged this as a duplicate, but since this alternative is also missing from that question I'll add it here. If I understand correctly why you would think this is interesting (having an arbitrary function that is applied sequentially to a list of values, accumulating the result), you should also look into reduce:
function sum(a, b) {
return a + b;
}
a = [2, 3, 4, 5, 3];
b = a.reduce(sum);
Another solution could be just calling the function without params in order to get the result but if you call it with params it adds to the sum.
function add() {
var sum = 0;
var closure = function() {
sum = Array.prototype.slice.call(arguments).reduce(function(total, num) {
return total + num;
}, sum);
return arguments.length ? closure : sum;
};
return closure.apply(null, arguments);
}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); // function(){}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;
We can make light work of it using a couple helper functions identity and sumk.
sumk uses a continuation to keep a stack of the pending add computations and unwinds the stack with 0 whenever the first () is called.
const identity = x => x
const sumk = (x,k) =>
x === undefined ? k(0) : y => sumk(y, next => k(x + next))
const sum = x => sumk(x, identity)
console.log(sum()) // 0
console.log(sum(1)()) // 1
console.log(sum(1)(2)()) // 3
console.log(sum(1)(2)(3)()) // 6
console.log(sum(1)(2)(3)(4)()) // 10
console.log(sum(1)(2)(3)(4)(5)()) // 15