Using pure function (For Each) to change array, failing Jest - javascript

I am trying to use a pure function that is using For Each, the function will change input array to return 'x'. Can someone help me explain why I am getting this error?
Functions:
let functions = {
helper: (x) => {
return x;
},
changeArray: (x) => {
let arr1 = [x];
arr1.forEach(functions.helper);
return arr1[0];
}
};
Test file:
test('For Each', () => {
expect(syntax.changeArray(['hey', 'hi']).toBe(['x','x']));
})
Result/Error:
TypeError: _syntax.default.changeArray is not a function
73 |
74 | test('For Each', () => {
> 75 | expect(syntax.changeArray(['hey', 'hi']).toBe(['x','x']));
| ^
76 | })
CHANGES:
const syntax{
helper: (x) => x,
changeArray: (arr) => {
return arr.map(syntax.helper);
}
}
TEST FILE:
test('For Each', () => {
expect(syntax.changeArray(['hey', 'hi'])).toBe(['x','x']);
})
RESULT:
expect(received).toBe(expected) // Object.is equality
- Expected
+ Received
Array [
- "x",
- "x",
+ "hey",
+ "hi",
]

There are multiple problems with this
Main one is, what is syntax.changeArray ? Your function is in functions.changeArray.
When you run a function through Array.forEach, the forEach function literally doesn't do anything with the returned value. I think what you want is Array.map
Also, your helper function returns x, not 'x' -- it will return whatever its given, so if you DID pass that helper function to array.map, it would just return the same unchanged value you send it.
This bit of code might hopefully give you an idea of what you should be doing.
function runMap(arr) {
return arr.map(val => 'x');
}
var testArray = [1,2,3];
console.log(runMap(testArray));

Why are we seeing references to both functions and syntax, which seem identical? Let's stick to one, and delete the other. I'll use syntax here.
Here's a definition of syntax that should fix your problems:
let syntax = {
// This change to the "helper" function solves problem #1;
// simply return the string 'x' regardless of the parameter
helper: x => 'x',
// This "changeArray" function return a new `Array` where
// every item has been mapped using `syntax.helper` (which
// will map every Array item to the string 'x'):
changeArray: arr => arr.map(syntax.helper)
};
Fix the logic error in your test suite. Change:
expect(syntax.changeArray(['hey', 'hi']).toBe(['x','x']))
To:
expect(syntax.changeArray(['hey', 'hi'])).toBe(['x','x']);

Related

How can I use for loop with array of string with filter?

I get array of strings as a parameter and I want to use filter for every each string in this array and return matched results.
get moviesByCity() {
return (id: string[]): MovieI[] | undefined => {
console.log(id);
for (let i = 0; i <= id.length; i++) {
console.log(id.length);
console.log(id[i]);
console.log(i);
return this.movies.filter((movie) => movie.city === id[i]);
}
};
}
The thing is my 'i' doesn't get iterated and it stays '0'. Where did i make a mistake?
I did console.log in the same order: 'id.length', 'id[i]' and 'i'
Not sure what you want intend to do, but here is my approximation.
Your have structurely messed up, using functions in wrong way.
Refer to docs for usage of functions like map, filter and some
const moviesByCity = (id: string[]): MovieI[] | undefined => {
console.log(id);
return id.map((e,idx)=>{
console.log(id[idx]);
console.log(e);
return movies.some((movie) => movie.city === e);
})
};

JavaScript function return False and 0 respectively

I am new to JavaScript and I am trying to write functional Programming to calculate if a number is Odd (isOdd) or not. I do not understand why I've got true and 0 or false and 1 when I called isOdd() twice in a row.
here is my code:
var mod = m => {return number => {return number % m }}
var eq = number1 => {return number2 => {return number1 === number2}}
var combine = (...fns) => { return arg => {for(let fn of fns.reverse()) arg = fn(arg); return arg;}}
var eq1 = eq(1)
var mod2 = mod(2)
var isOdd = combine(eq1, mod2)
mod2(4) -----> returns 0
mod2(3) -----> returns 1
eq1(1) -----> returns true
eq1(2) -----> returns false
isOdd(1) returns true
isOdd(1) returns 1 (what??)
I can not understand what I missed or what goes wrong. I tested this code in most browsers.
Appreciate if someone can explain in details.
I can wrap isOdd again and have something like
isOdd = (number) => {return Boolean(combine(eq1, mod2))}
that returns boolean value everytime. But I want to understand what I missed in the first place/
Array.prototype.reverse reverses the fns array in-place. You’re calling .reverse on fns every time you call isOdd, even though you pass a fixed argument list of functions in combine once. That list is scoped to combine and reversed on every call of isOdd(1).
In other words, your first isOdd(1) call remembers the fns array of your original combine(eq1, mod2) call. fns is [ eq1, mod2 ]. Then you call fns.reverse() to iterate over it; but this mutates fns to [ mod2, eq1 ]. You get the correct result, because you wanted to call the functions in reverse order. The resulting call is eq1(mod2(1)) === eq1(1) === true.
In your second isOdd(1) call, however, fns is still remembered, and it still has the reversed [ mod2, eq1 ] value, because its scope is combine, so another isOdd call doesn’t reset the originally passed fns. The second isOdd call reverses this array again because fns.reverse is called within isOdd. The resulting call is mod2(eq1(1)) === mod2(true) === 1 (because true % 2 is coerced to 1 % 2).
A working function would look like this:
const combine = (...fns) => {
const reversedFns = fns.reverse();
return (arg) => {
for(let fn of reversedFns){
arg = fn(arg);
}
return arg;
};
};
A simpler approach uses Array.prototype.reduceRight:
const combine = (...fns) => (arg) => fns.reduceRight((result, fn) => fn(result), arg);
Since you want to aggregate multiple operations onto a single result based on a list from right to left, reduceRight is the perfect method for this. You start with arg, go through the list of functions from right to left, then call the current function with arg, and that becomes the new arg for the next function. The final result is returned. All this is captured by the code fns.reduceRight((result, fn) => fn(result), arg).

Calling a JavaScript function several times (ex: myFunc(1,2,3)(1,2)(2); ) [duplicate]

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

Defer execution for ES6 Template Literals

I am playing with the new ES6 Template Literals feature and the first thing that came to my head was a String.format for JavaScript so I went about implementing a prototype:
String.prototype.format = function() {
var self = this;
arguments.forEach(function(val,idx) {
self["p"+idx] = val;
});
return this.toString();
};
console.log(`Hello, ${p0}. This is a ${p1}`.format("world", "test"));
ES6Fiddle
However, the Template Literal is evaluated before it's passed to my prototype method. Is there any way I can write the above code to defer the result until after I have dynamically created the elements?
I can see three ways around this:
Use template strings like they were designed to be used, without any format function:
console.log(`Hello, ${"world"}. This is a ${"test"}`);
// might make more sense with variables:
var p0 = "world", p1 = "test";
console.log(`Hello, ${p0}. This is a ${p1}`);
or even function parameters for actual deferral of the evaluation:
const welcome = (p0, p1) => `Hello, ${p0}. This is a ${p1}`;
console.log(welcome("world", "test"));
Don't use a template string, but a plain string literal:
String.prototype.format = function() {
var args = arguments;
return this.replace(/\$\{p(\d)\}/g, function(match, id) {
return args[id];
});
};
console.log("Hello, ${p0}. This is a ${p1}".format("world", "test"));
Use a tagged template literal. Notice that the substitutions will still be evaluated without interception by the handler, so you cannot use identifiers like p0 without having a variable named so. This behavior may change if a different substitution body syntax proposal is accepted (Update: it was not).
function formatter(literals, ...substitutions) {
return {
format: function() {
var out = [];
for(var i=0, k=0; i < literals.length; i++) {
out[k++] = literals[i];
out[k++] = arguments[substitutions[i]];
}
out[k] = literals[i];
return out.join("");
}
};
}
console.log(formatter`Hello, ${0}. This is a ${1}`.format("world", "test"));
// Notice the number literals: ^ ^
Extending #Bergi 's answer, the power of tagged template strings reveals itself when you realize you can return anything as a result, not only plain strings. In his example, the tag constructs and returns an object with a closure and function property format.
In my favorite approach, I return a function value by itself, that you can call later and pass new parameters to fill the template. Like this:
function fmt([fisrt, ...rest], ...tags) {
return values => rest.reduce((acc, curr, i) => {
return acc + values[tags[i]] + curr;
}, fisrt);
}
Or, for the code golfers:
let fmt=([f,...r],...t)=>v=>r.reduce((a,c,i)=>a+v[t[i]]+c,f)
Then you construct your templates and defer the substitutions:
> fmt`Test with ${0}, ${1}, ${2} and ${0} again`(['A', 'B', 'C']);
// 'Test with A, B, C and A again'
> template = fmt`Test with ${'foo'}, ${'bar'}, ${'baz'} and ${'foo'} again`
> template({ foo:'FOO', bar:'BAR' })
// 'Test with FOO, BAR, undefined and FOO again'
Another option, closer to what you wrote, would be to return a object extended from a string, to get duck-typing out of the box and respect interface. An extension to the String.prototype wouldn't work because you'd need the closure of the template tag to resolve the parameters later.
class FormatString extends String {
// Some other custom extensions that don't need the template closure
}
function fmt([fisrt, ...rest], ...tags) {
const str = new FormatString(rest.reduce((acc, curr, i) => `${acc}\${${tags[i]}}${curr}`, fisrt));
str.format = values => rest.reduce((acc, curr, i) => {
return acc + values[tags[i]] + curr;
}, fisrt);
return str;
}
Then, in the call-site:
> console.log(fmt`Hello, ${0}. This is a ${1}.`.format(["world", "test"]));
// Hello, world. This is a test.
> template = fmt`Hello, ${'foo'}. This is a ${'bar'}.`
> console.log(template)
// { [String: 'Hello, ${foo}. This is a ${bar}.'] format: [Function] }
> console.log(template.format({ foo: true, bar: null }))
// Hello, true. This is a null.
You can refer to more information and applications in this other answer.
AFAIS, the useful feature "deferred execution of string templates" is still not available. Using a lambda is an expressive, readable and short solution, however:
var greetingTmpl = (...p)=>`Hello, ${p[0]}. This is a ${p[1]}`;
console.log( greetingTmpl("world","test") );
console.log( greetingTmpl("#CodingIntrigue","try") );
You can inject values into string using below function
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
// --- Examples ---
// parameters in object
let t1 = 'My name is ${name}, I am ${age}. My brother name is also ${name}.';
let r1 = inject(t1, {name: 'JOHN',age: 23} );
console.log("OBJECT:", r1);
// parameters in array
let t2 = "Today ${0} saw ${2} at shop ${1} times - ${0} was haapy."
let r2 = inject(t2, {...['JOHN', 6, 'SUsAN']} );
console.log("ARRAY :", r2);
I also like the idea of the String.format function, and being able to explicitly define the variables for resolution.
This is what I came up with... basically a String.replace method with a deepObject lookup.
const isUndefined = o => typeof o === 'undefined'
const nvl = (o, valueIfUndefined) => isUndefined(o) ? valueIfUndefined : o
// gets a deep value from an object, given a 'path'.
const getDeepValue = (obj, path) =>
path
.replace(/\[|\]\.?/g, '.')
.split('.')
.filter(s => s)
.reduce((acc, val) => acc && acc[val], obj)
// given a string, resolves all template variables.
const resolveTemplate = (str, variables) => {
return str.replace(/\$\{([^\}]+)\}/g, (m, g1) =>
nvl(getDeepValue(variables, g1), m))
}
// add a 'format' method to the String prototype.
String.prototype.format = function(variables) {
return resolveTemplate(this, variables)
}
// setup variables for resolution...
var variables = {}
variables['top level'] = 'Foo'
variables['deep object'] = {text:'Bar'}
var aGlobalVariable = 'Dog'
// ==> Foo Bar <==
console.log('==> ${top level} ${deep object.text} <=='.format(variables))
// ==> Dog Dog <==
console.log('==> ${aGlobalVariable} ${aGlobalVariable} <=='.format(this))
// ==> ${not an object.text} <==
console.log('==> ${not an object.text} <=='.format(variables))
Alternatively, if you want more than just variable resolution (e.g. the behaviour of template literals), you can use the following.
N.B. eval is considered 'evil' - consider using a safe-eval alternative.
// evalutes with a provided 'this' context.
const evalWithContext = (string, context) => function(s){
return eval(s);
}.call(context, string)
// given a string, resolves all template variables.
const resolveTemplate = function(str, variables) {
return str.replace(/\$\{([^\}]+)\}/g, (m, g1) => evalWithContext(g1, variables))
}
// add a 'format' method to the String prototype.
String.prototype.format = function(variables) {
return resolveTemplate(this, variables)
}
// ==> 5Foobar <==
console.log('==> ${1 + 4 + this.someVal} <=='.format({someVal: 'Foobar'}))
I posted an answer to a similar question that gives two approaches where the execution of the template literal is delayed. When the template literal is in a function, the template literal is only evaluated when the function is called, and it is evaluated using the scope of the function.
https://stackoverflow.com/a/49539260/188963
Although this question is already answered, here I have a simple implementations I use when I load configuration files (the code is typescript, but it is very easy to convert into JS, just remove the typings):
/**
* This approach has many limitations:
* - it does not accept variable names with numbers or other symbols (relatively easy to fix)
* - it does not accept arbitrary expressions (quite difficult to fix)
*/
function deferredTemplateLiteral(template: string, env: { [key: string]: string | undefined }): string {
const varsMatcher = /\${([a-zA-Z_]+)}/
const globalVarsmatcher = /\${[a-zA-Z_]+}/g
const varMatches: string[] = template.match(globalVarsmatcher) ?? []
const templateVarNames = varMatches.map(v => v.match(varsMatcher)?.[1] ?? '')
const templateValues: (string | undefined)[] = templateVarNames.map(v => env[v])
const templateInterpolator = new Function(...[...templateVarNames, `return \`${template}\`;`])
return templateInterpolator(...templateValues)
}
// Usage:
deferredTemplateLiteral("hello ${thing}", {thing: "world"}) === "hello world"
Although it's possible to make this stuff more powerful & flexible, it introduces too much complexity and risk without much benefit.
Here a link to the gist: https://gist.github.com/castarco/94c5385539cf4d7104cc4d3513c14f55
(see #Bergi's very similar answer above)
function interpolate(strings, ...positions) {
var errors = positions.filter(pos=>~~pos!==pos);
if (errors.length) {
throw "Invalid Interpolation Positions: " + errors.join(', ');
}
return function $(...vals) {
var output = '';
for (let i = 0; i < positions.length; i ++) {
output += (strings[i] || '') + (vals[positions[i] - 1] || '');
}
output += strings[strings.length - 1];
return output;
};
}
var iString = interpolate`This is ${1}, which is pretty ${2} and ${3}. Just to reiterate, ${1} is ${2}! (nothing ${0} ${100} here)`;
// Sets iString to an interpolation function
console.log(iString('interpolation', 'cool', 'useful', 'extra'));
// Substitutes the values into the iString and returns:
// 'This is interpolation, which is pretty cool and useful.
// Just to reiterate, interpolation is cool! (nothing here)'
The main difference between this and #Bergi's answer is how errors are handled (silently vs not).
It should be easy enough to expand this idea into a syntax that accepts named arguments:
interpolate`This is ${'foo'}, which is pretty ${'bar'}.`({foo: 'interpolation', bar: 'cool'});
https://github.com/spikesagal/es6interpolate/blob/main/src/interpolate.js

Closure in JavaScript - whats wrong?

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

Categories