Related
So I want to know if it's possible to create a scenario like this in javascript:
Lets say I have two arrays:
a = [1, 2, 3]
b = [4, 5, 6]
And then I would like to create an array c that references the two arrays:
c = [1, 2, 3, 4, 5, 6]
However when I change an element in one of the two arrays I would also like to have it automatically affect array c:
a[1] = 1
c = [1, 1, 3, 4, 5, 6]
Is there a way to make this possible in javascript?
The traditional pass-by-reference approach doesn't exist in JavaScript, so you'll have to use a workaround. The simplest way would be to return c dynamically as a combination of a and b using a function. Another would be using an object and getter/setters to manipulate what you get when accessing c.
Example:
var $ = (function () {
/* Hidden arrays */
var a = [1, 2, 3];
var b = [4, 5, 6];
/* Visible object. */
return {
get a () {
return a;
},
set a (v) {
a = v;
},
get b () {
return b;
},
set b (v) {
b = v;
},
get c () {
return a.concat(b);
},
};
})();
/* Example */
console.log(JSON.stringify($.a), JSON.stringify($.b), JSON.stringify($.c));
$.a = [0, 1, 2];
console.log(JSON.stringify($.a), JSON.stringify($.b), JSON.stringify($.c));
$.b[1] = 7;
console.log(JSON.stringify($.a), JSON.stringify($.b), JSON.stringify($.c));
You will need a Proxy.
const a = [1,2,3];
const b = [4,5,6];
const c = new Proxy([a,b], {
_localIndex: function(arrays, index) {
index = +index;
if( isNaN(index)) throw new TypeError("Expected numeric index");
if( Math.floor(index) !== index) throw new RangeError("Index must be an integer");
if( index < 0) throw new RangeError("Index must be positive");
for( let i=0; i<arrays.length; i++) {
if( arrays[i].length > index) return [i,index];
index -= arrays[i].length;
}
throw new RangeError("Index out of bounds");
},
get: function(arrays, index) {
if( index === "length") {
return arrays.reduce((a,c)=>a+c.length,0);
}
if( index === "source") {
return arrays;
}
const [arr, idx] = this._localIndex(arrays, index);
return arrays[arr][idx];
},
set: function(arrays, index, value) {
const [arr, idx] = this._localIndex(arrays, index);
arrays[arr][idx] = value;
}
});
console.log("Get c[4]: "+c[4]);
c[2] = 9;
console.log("Updated c[2], a is now: "+JSON.stringify(a));
console.log("Get c's source array: "+JSON.stringify(c.source));
a.push('x');
console.log("Pushed value to a, c is now: "+JSON.stringify(c.source));
MDN docs
function revertNumbers(...numberArray) {
let rev = [];
for(let i = 0; i <numberArray.length; i++)
{
rev.push(numberArray[i])
}
return rev.reverse();
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
Can you please show me the how to reverse number in this code that the statement will be true? Also without using .reverse method. Is it possible to make it in another for loop by just changing this statement:
(let i = 0; i <numberArray.length; i++)
You just need to reverse the direction of your loop. Means start i with last index and then gradually decrease it to 0
function revertNumbers(...numberArray) {
let rev = [];
for(let i = numberArray.length - 1; i >= 0; i--)
{
rev.push(numberArray[i])
}
return rev.join(",")
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
This is also a good use case of reduceRight()
const revertNumbers = (...arr) => arr.reduceRight((ac, a) => ([...ac, a]), []).join(',')
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
Here is a solution that manipulates the array in place, and only has to traverse half of the original array in order to reverse it. This ekes out some modest performance gains compared to other answers in this thread (my function narrowly beats out or matches the speed of even the native reverse method in ops/sec), but micro-optimizations are largely irrelevant for this problem unless you are talking about a truly massive list of numbers.
Nonetheless, here is my answer:
const revNums = (...numArray) => {
for (
let arrLen = numArray.length,
breakPoint = ((arrLen / 2)|0) - 1,
i = arrLen,
k = 0,
temp;
--i !== breakPoint;
++k
) {
temp = numArray[i];
numArray[i] = numArray[k];
numArray[k] = temp;
}
return numArray.join(',');
};
You could reduce the original array and unshift each element onto the new array.
function revertNumbers(...numberArray) {
return numberArray.reduce((r, e) => { r.unshift(e); return r }, []).join(',')
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0")
If you don't want to unshift, you can concat in reverse.
function revertNumbers(...numberArray) {
return numberArray.reduce((r, e, i, a) => r.concat(a[a.length - i - 1]), []).join(',')
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0")
You could take a value and the rest of the arguments and use a recursive approach to get a reversed array of arguments.
function revertNumbers(v, ...rest) {
return rest.length
? [...revertNumbers(...rest), v]
: [v];
}
console.log(revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
It is to ask how many solutions can be possible ?
here are 3 of them...
"use strict";
const targetString = '9,8,7,6,5,4,3,2,1,0'
;
function soluce_1(...numberArray)
{
const rev = [];
for( let i=numberArray.length;i--;) { rev.push(numberArray[i]) }
return rev.join(',')
}
function soluce_2(...numberArray)
{
const rev = [];
let pos = numberArray.length;
for(let N in numberArray) { rev[--pos] = N }
return rev.join(",")
}
function soluce_3(...numberArray)
{
const rev = [];
while(numberArray.length) { rev.push(numberArray.pop()) }
return rev.join(',')
}
console.log('soluce_1 ->', (soluce_1(0,1,2,3,4,5,6,7,8,9)===targetString) );
console.log('soluce_2 ->', (soluce_2(0,1,2,3,4,5,6,7,8,9)===targetString) );
console.log('soluce_3 ->', (soluce_3(0,1,2,3,4,5,6,7,8,9)===targetString) );
And yes, I code in Whitesmiths style, please respect this (the reason for the downVote for correct answers ?)
https://en.wikipedia.org/wiki/Indentation_style#Whitesmiths_style
You might reverse like this:
function reverse(...a) {
const h = a.length >> 1, l = a.length-1;
for (let i = 0; i < h; ++i) [a[i], a[l-i]] = [a[l-i], a[i]];
return a;
}
console.log(reverse(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).join(','));
var o = [1,2,3,5,6,7,8]
var res = o.reduce(function(x,y){
return !((y-x)===1)?y-1:'Nothing'
})
console.log(res)//7
Output should be 4, want to know if it is possible using reduce or functionally (Not through loops)? it only works if the missing value is before the last value of an array.
You can use reduce to compute the actual sum of all elements and then subtract it from the target sum (n(a0+an)/2). This gives you the missing number.
var o = [1,2,3,5,6,7,8];
var len = o.length;
var sum = (len + 1) * (o[0] + o[len - 1]) / 2;
var res = sum - o.reduce((x,y) => x + y);
console.log(res);
Note that this works with any starting value and any step, e.g. for [3,5,7,11] it will correctly print 9. The only requirement is that o should be an arithmetic progression.
You could use a start value and check the previous element and the actual element.
var o = [1, 2, 3, 5, 6, 7, 8],
res = o.reduce(function(r, a, i, aa) {
return !i || r !== undefined || aa[i - 1] + 1 === a ? r : aa[i - 1] + 1;
}, undefined);
console.log(res);
Instead of reduce you could use find, which will not look any further once it finds a missing value:
const o = [1,2,3,5,6,7,8];
const res = o.find( (x,i) => o[i+1]-x > 1 ) + 1;
console.log(res)//4
It's always good to generalize these jobs. So you should provide a series descriptor function for the algorithm to find which item is missing in the series. Let's do it;
function findMissingItem(a,s){
return s(a[a.findIndex((f,i,a) => i ? f !== s(a[i-1]) : false)-1]);
}
var data1 = [1,2,3,5,6,7,8],
data2 = [1,4,9,16,36,49,64,81],
series1 = n => n+1,
series2 = n => Math.pow(Math.sqrt(n)+1,2);
res1 = findMissingItem(data1,series1),
res2 = findMissingItem(data2,series2);
console.log(res1);
console.log(res2);
Here's a simple solution using Array.reduce and the ES6 arrow function for brevity.
const array = [1, 2, 3, 5, 6, 7, 8];
const result = array.reduce((result, x) => x > result ? result : x + 1, 1)
console.log(result); // 4
With a little refactoring, we can start to make the solution more generic.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(missingLinkReducer, sequence[0])
function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
function nextValue(value) {
return value + 1;
}
console.log(result);
Going a little bit further, we can make it so that different functions can be plugged in for calculating the next value.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(createMissingLinkReducer(increment), sequence[0]);
console.log(result + ' is missing from ' + sequence);
const sequenceB = [1, 2, 4, 8, 16, 64, 128];
const resultB = sequenceB.reduce(createMissingLinkReducer(double), sequenceB[0]);
console.log(resultB + ' is missing from ' + sequenceB);
function createMissingLinkReducer(nextValue) {
return function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
}
function increment(value) {
return value + 1;
}
function double(value) {
return value * 2;
}
You can use every for this, below will work for any sequence interval you specify - it will return -1 if all elements are in sequence, or the element that doesn't fit:
var o = [1, 4, 7, 10, 11]
var seqInterval = 3;
function getMissing(arr, interval) {
var hit = -1;
var res = arr.every(function(e, i) {
hit = i === 0 ? hit : ((e - interval) === arr[i - 1] ? -1 : e);
return hit === -1;
});
return hit;
}
console.log(getMissing(o, seqInterval));
var o1 = [1,2,3,5,6,7,8];
var seqInterval1 = 1;
console.log(getMissing(o1, seqInterval1));
I'd like to write a function in Javascript that allows me to pass in a mathematical operator and a list of ints and for each item in that list, apply the operator to it.
Thinking of it in terms of a sum, this is what I've come up with:
function accumulate(list, operator){
var sum = 0;
for each(var item in list){
sum = accumulator(sum, item);
}
print(sum);
}
Testing this code produces the following error:
var list = new Array();
list[0] = 1;
list[1] = 2;
list[2] = 3;
js> accumulate(list, +);
js: "<stdin>", line 9: syntax error
js: accumulate(list, +);
js: ..................^
js: "<stdin>", line 9: Compilation produced 1 syntax errors.
You can't pass an operator as a parameter, but you can pass a function:
function accumulate(list, accumulator){ // renamed parameter
var sum = 0;
for(var i = 0; i < list.length; i++){ // removed deprecated for…each loop
sum = accumulator(sum, list[i]);
}
print(sum);
}
accumulate(list, function(a, b) { return a + b; });
This is pretty close to what the Array.prototype.reduce function does, though not exactly. To mimic the behavior of reduce, you'd have to get the first element from list and use that as the seed for your accumulator, rather than always using 0:
function accumulate(list, accumulator, seed){
var i = 0, len = list.length;
var acc = arguments.length > 2 ? seed : list[i++];
for(; i < len; i++){
acc = accumulator(acc, list[i]);
}
print(acc);
}
This way, you could compute the product of list (your method would always return 0):
accumulate(list, function(a, b) { return a * b; });
Update: If you're developing for newer browsers that support ECMAScript 2015 / ES6 (or using a transpiler like Babel), you can also use 'arrow function' syntax to make your code a bit more compact:
accumulate(list, (a, b) => a * b);
If all the operations you are planning to do are binary operations, then you can do this
var operations = {
"+" : function (operand1, operand2) {
return operand1 + operand2;
},
"-" : function (operand1, operand2) {
return operand1 - operand2;
},
"*" : function (operand1, operand2) {
return operand1 * operand2;
}
};
function accumulate(list, operator) {
return list.reduce(operations[operator]);
}
console.log(accumulate([1, 2, 3, 4], "+")); // 10
console.log(accumulate([1, 2, 3, 4], "-")); // -8
console.log(accumulate([1, 2, 3, 4], "*")); // 24
I think you can do that in several different ways, but I would suggest you something like this:
var operatorFunction = {
'+' : function(x, y) {
return x + y;
},
'-' : function(x, y) {
return x - y;
},
'*' : function(x, y) {
return x * y;
}
};
function accumul(list, neutral, operator) {
var sum = neutral;
list.forEach(function(item) {
sum = operatorFunction[operator](sum, item);
});
return sum;
}
console.log(accumul([2, 3, 4], 0, '+'));
console.log(accumul([2, 3, 4], 0, '-'));
console.log(accumul([2, 3, 4], 1, '*'));
console.log(accumul([], 0, '+'));
console.log(accumul([], 1, '*'));
In the example above, you just need something like accumul([2, 3, 4], 0, '+'); to call you function. operatorFunction[operator] calls the correspondent operator function.
Running the example in the command line, with node.js, gives:
$ node accumulate.js
9
-9
24
0
1
This version also work if the array is empty. You can not use list.reduce if the list is empty.
I know this is an old question. Just adding some more information.
If you often use operators and need to reduce the results (accumulate), it is highly recommended to develop different helpers, so you can quickly use any input form to obtain the results.
Although, this will not be always the case when you use reduce, the following helper will allow to pass the first element of your array as default value:
reducer = (list, func) => list.slice(1).reduce(func, list.slice(0, 1).pop())
The above, still has a function dependency, so you still need to declare the specific function that wraps your target operator:
sum = list => reducer(list, (a, b) => a + b)
sum([1, 2, 3, 4, 5])
You could then redefine sum, for example, as per new input formats you see will be backwards compatible. In this example by using a new helper, flat (still experimental as per now; added the code):
flat = (e) => Array.isArray(e) ? [].concat.apply([], e.map(flat)) : e
sum = (...list) => reducer(flat(list), (a, b) => a + b)
mult = (...list) => reducer(flat(list), (a, b) => a * b)
sum([1, 2, 3, 4, 5])
sum(1, 2, 3, 4, 5)
mult([1, 2, 3, 4, 5])
mult(1, 2, 3, 4, 5)
Then you can use reducer (or any variant you may find more useful) to simplify the definition of other helpers as well. Just one last example with matrix custom operators (in this case, they are functions):
zip = (...lists) => lists[0].map((_l, i) => lists.map(list => list[i]))
dot_product = (a, b) => sum(zip(a, b).map(x => mult(x)))
mx_transpose = (mx) => zip.apply([], mx)
// the operator
mx_product = (m1, m2) =>
m1.map(row => mx_transpose(m2).map(
col => dot_product(row, col) ))
// the reducer
mx_multiply = (...mxs) => reducer(mxs, (done, mx) => mx_product(done, mx))
A = [[2, 3, 4],
[1, 0, 0]]
B = [[0, 1000],
[1, 100],
[0, 10]]
C = [[2, 0],
[0, 0.1]]
JSON.stringify(AB = mx_product (A, B))
JSON.stringify(ABC = mx_product (AB, C))
JSON.stringify(ABC2 = mx_multiply(A, B, C))
just pass 1 or -1 as input then multiply all items with this after wh.
var list = { a: 3, b: 7, c: 5 }
var expression = (a) => a * 2;
function computeObject(list, bc){
for(var x in list){
list[x] = bc(list[x]);
console.log(list[x]);
}
}
computeObject(list, expression);
It can be done pretty decent using currying:
const calculate = a => str => b => {switch(str) {
case '+': return a + b
case '-': return a - b
case '/': return a / b
case '*': return a * b
default: return 'Invalid operation'
}}
const res = calculate(15)('*')(28)
console.log('15 * 28 =', res)
Unfortunately, its not really possible to do this like you are trying to do. What I would do is pass in a number, and have a if/then or a switch/case to decide what to do based on that number
Is there some way to "wrap" a recursive function via a higher-order function, so that the recursive call is also wrapped? (e.g. to log the arguments to the function on each call.)
For example, suppose we have a function, sum(), that returns the sum of a list of numbers by adding the head to the sum of the tail:
function sum(a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + sum(a.slice(1));
}
}
Is there some way to write a higher-order function, logging(), that takes the sum() function as input, and returns a function that outputs the arguments to sum() on each recursive call?
The following does not work:
function logging(fn) {
return function(a) {
console.log(a);
return fn(a);
}
}
sum2 = logging(sum);
sum2([1, 2, 3]);
Actual output:
[1, 2, 3]
-> 6
Expected output:
[1, 2, 3]
[2, 3]
[3]
[]
-> 6
Is this even possible if sum() is rewritten so that it can be used with Y Combinator-style "recursion"?
function sum_core(g) {
return function (a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + g(a.slice(1));
}
};
}
sum = Y(sum_core);
sum([1, 2, 3]);
// -> 6
I know this is kind of a non-answer but what you want is much easier to do if you use objects and dynamically dispatched methods. Essentially, we store "rec" in a mutable cell instead of having to pass it around.
It would be kind of similar to sum = logging(sum) (instead of sum2 =) but is more idiomatic and doesn't hardcode the name for the mutable reference we dispatch on.
var obj = {
sum : function(a){
if (a.length === 0) {
return 0;
} else {
return a[0] + this.sum(a.slice(1)); // <-- dispatch on `this`
}
}
}
function add_logging(obj, funcname){
var oldf = obj[funcname];
obj[funcname] = function(/**/){
console.log(arguments);
return oldf.apply(this, arguments);
}
}
add_logging(obj, 'sum');
Let's start backwards. Say you want a function traceSum:
> traceSum([1, 2, 3]);
[1, 2, 3]
[2, 3]
[3]
[]
6
You could implement traceSum as follows:
function traceSum(a) {
console.log(a);
if (a.length === 0) return 0;
else return a[0] + traceSum(a.slice(1));
}
From this implementation we can create a generalized trace function:
function trace(f) {
return function (a) {
console.log(a);
return f(trace(f), a);
};
}
This is similar to the way the Y combinator is implemented in JavaScript:
function y(f) {
return function (a) {
return f(y(f), a);
};
}
Your traceSum function can now be implemented as:
var traceSum = trace(function (traceSum, a) {
if (a.length === 0) return 0;
else return a[0] + traceSum(a.slice(1));
});
Unfortunately if you can't modify the sum function then you can't trace it since you need some way to specify which function to callback dynamically. Consider:
function sum(a) {
if (a.length === 0) return 0;
else return a[0] + sum(a.slice(1));
}
You cannot trace the above function because inside the function sum will always refer to the function itself. There's no way to specify the value of sum dynamically.
function sum(a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + sum(a.slice(1));
}
}
var dummySum = sum, sum = function(args) {
console.log(args);
return dummySum(args);
};
console.log(sum([1, 2, 3]));
Output
[ 1, 2, 3 ]
[ 2, 3 ]
[ 3 ]
[]
6
If you insist on using regular functions without using "this", the only way I can think of is applying the logging combinator before you tie the knot with the recursion (Y) combinator.
Basically, we need to use dynamic dispatching in the logger just like we used dynamic dispatching in the sum function itself.
// f: function with a recursion parameter
// rec: function without the recursion parameter
var sum = function(rec, a){
if (a.length === 0) {
return 0;
} else {
return a[0] + rec(a.slice(1));
}
};
var logging = function(msg, f){
return function(rec, x){
console.log(msg, x);
return f(rec, x);
}
}
var Y = function(f){
var rec = function(x){
return f(rec, x);
}
return rec;
}
//I can add a bunch of wrappers and only tie the knot with "Y" in the end:
console.log( Y(logging("a", logging("b", sum)))([1,2,3]) );
Output
a [1, 2, 3]
b [1, 2, 3]
a [2, 3]
b [2, 3]
a [3]
b [3]
a []
b []
6
We could also extend Y and logging to be variadic but it would make the code a bit more complicated.
If you cannot change the sum function
function sum(a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + sum(a.slice(1));
}
}
then it's impossible. Sorry
edit
Ugly but works. Don't do that ^^
function rest(a) {
console.log(a);
sum(a, rest);
}
function sum(a, rest) {
if (a.length === 0) {
return 0;
} else {
return a[0] + rest(a.slice(1));
}
}
But looks at http://www.nczonline.net/blog/2009/01/20/speed-up-your-javascript-part-2/
Search for memoizer, I'll read it too.
It is not possible in JavaScript without modifying the function. If you don't want the manual work, your best bet is something like that:
function logged(func){
return eval("("+func.toString().replace(/function(.*){(.*)/g,"function$1{console.log(arguments);$2")+")");
};
Then you can use it like:
function sum(a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + sum(a.slice(1));
}
}
console.log(logged(sum)([1,2,3,4]));
Which outputs:
{ '0': [ 1, 2, 3, 4 ] }
{ '0': [ 2, 3, 4 ] }
{ '0': [ 3, 4 ] }
{ '0': [ 4 ] }
{ '0': [] }
10
logged itself is very slow because it recompiles the function (with eval), but the resulting function is as fast as if you defined it manually. So, use logged only once per function and you are fine.
Scope issue. Try to do the following:
function logging(fn) {
var _fn = fn; // local cached copy
return function(a) {
console.log(a);
return _fn(a);
}
}