Related
There is an algorithm question asking to sort a matrix diagonally. I'm not finding a solution for this quesiton.
const matrix =
[
[1, 3, 9, 4],
[9, 5, 7, 7],
[3, 6, 9, 7],
[1, 2, 2, 2]
]
Should output:
[
[1, 9, 9, 7],
[3, 5, 6, 9],
[3, 4, 7, 7],
[1, 2, 2, 2]
]
My code so far:
function diagonalSort(matrix) {
const cols = matrix[0].length;
const rows = matrix.length;
const maxLength = Math.max(cols, rows);
let temp;
for (let k = 0; k <= 2 * (maxLength - 1); k++) {
temp = [];
for (let y = cols - 1; y >= 0; y--) {
let x = k - y;
// console.log(k, y, x);
if (x >= 0 && x < rows) {
temp.push(matrix[y][x]);
}
}
if (temp.length > 0) {
console.log(temp);
}
}
}
Which outputs this:
[ 1 ]
[ 3, 9 ]
[ 3, 5, 9 ]
[ 1, 4, 6, 7 ]
[ 2, 7, 9 ]
[ 2, 7 ]
[ 2 ]
But how to put it back together...?
This approach is also a gentle introduction to functional lenses in Javascript:
const range = (lo, hi) => [...Array (hi - lo)] .map ((_, i) => i + lo)
const diagonals = (rows, cols) =>
range (0, rows + cols - 1) .map (
d => range (Math.max (d - rows + 1, 0), Math.min (d, cols - 1) + 1)
.map (x => [d - x, x])
)
const coordLens = (coords) => ({
get: (m) => coords .map (([x, y]) => m [x] [y]),
set: (arr, m) => coords .reduce (
(m, [x, y], i) => {m [x] [y] = arr [i]; return m},
m .map (r => [... r]) // cheap clone
),
})
const diagonalLenses = (rows, cols) =>
diagonals (rows, cols) .map (coordLens)
const sortMatrix = (comparator) => (m) =>
diagonalLenses (m.length, m[0].length)
.reduce ((m, lens) => lens.set (lens .get (m) .sort (comparator), m), m)
const numericSorter = (a, b) => a - b
console .log (
sortMatrix (numericSorter) ([
[1, 3, 9, 4],
[9, 5, 7, 7],
[3, 6, 9, 7],
[1, 2, 2, 2]
])
.map (r => r .join (' ')) .join ('\n')
)
After the minor helper function range (which works like range (3. 12) ==> [3, 4 , 5, 6, 7, 8, 9, 10, 11]) (including the start, excluding the stop) we have diagonals, which calculates the diagonals as arrays of [x, y] pairs, given the height and width of a matrix.
The most important bit here is coordLens. A lens is a glorified getter/setter pair for some facet of a data structure. They turn out to be quite useful. Many of the standard introductions to them point to a single property or array index, or perhaps a nested path inside an object. These are slightly more interesting. coordLens takes an array of [x, y] coordinates and returns a lens that we can use to extract the values at those coordinates from a given matrix, or to set the values in (a copy of) a matrix from elements supplied as an array.
On top of these two we build diagonalLenses, which takes the number of rows and columns and creates an array of coordinate lenses, one for each diagonal.
We build the main function sortMatrix on these functions. We accept a standard comparator and return a function that takes a matrix and returns another of the same shape, with each of the southwest -> northeast diagonals sorted. We create an array of lenses using diagonalLenses. Then for each lens, we get the values, sort them and use the set method to update our cloned matrix with the sorted values.
Note that there is little error-checking in any of this. The pieces will work together in the manner described here, but coordLens should, if used more generically, check that the array values it's trying to receive or to set are within bounds.
Addendum - the use of lenses
I originally wanted to explain the use of lenses in greater depth. But it was bedtime and I left it with just a brief description. There are many tutorials available to cover the basics. But very, very briefly, lenses are structures that focus on one aspect of a data structure. You create one by supplying a getter and a setter for your aspect, and then you can use a consistent interface to read, write, and modify data. (In the write/modify cases, this would involve creating a copy of the object. There's no mutation involved; we're not barbarians!)
What I am taking advantage of here is that the lenses don't have to be as simple as tends to be shown in those tutorials. Instead of pointing to a single property of an object, they can do more. One of my favorite examples is that a weather app which -- as is only sensible -- reports temperatures in Celsius, but which has users who live in a benighted country like by own, who only know Fahrenheit.
const fahrenLens = lens(
obj => obj.temp * 9 / 5 + 32,
(degF, obj) => ({...obj, temp: (degF - 32) * 5 / 9})
)
And it can be used like this:
const nyc= {name: 'New York', lat: 40.730610, lng: -73.935242, temp: 25}
view (fahrenLens, nyc) //=> 77
set (fahrenLens, 86, nyc)
//=> {name: "New York", lat: 40.73061, lng: -73.935242, temp: 30}
over (fahrenLens, t => t - 27, nyc)
//=> {name: "New York", lat: 40.73061, lng: -73.935242, temp: 10}
This uses three standard function for working with lenses, which, in our simple lens implementation might look like this:
const view = (lens, o) => lens .get (o)
const set = (lens, v, o) => lens .set (v, o)
const over = (lens, f, o) => lens .set (f (lens .get (o)), o)
In the answer above we use lenses to track multiple coordinates in an m x n grid, using this code:
const coordLens = (coords) => ({
get: (m) => coords .map (([x, y]) => m [x] [y]),
set: (arr, m) => coords .reduce (
(m, [x, y], i) => {m [x] [y] = arr [i]; return m},
m .map (r => [... r]) // cheap clone
),
})
Given a set of coordinates, when we view a matrix through this coordinate lens, we get back an array of the values at those coordinates. When we set the matrix with an array of values through this lens, we fold the array of values into a new matrix by setting each coordinate to the corresponding array value, starting with a copy of the matrix.
Using diagonalLenses, we create an array of coordinate lenses, one for each diagonal in the grid. (Here considering only on southwest -> northeast diagonals.) If we were to use our over function we could simplify further to
const sortMatrix = (comparator) => (m) =>
diagonalLenses (m)
.reduce ((m, lens) => over (lens, xs => xs.sort (comparator), m), m)
And my own preference would be to introduce a sort function like
const sort = (comparator) => (xs) => [...xs] .sort (comparator)
which would allow us to simplify that further to
const sortMatrix = (comparator) => (m) =>
diagonalLenses (m)
.reduce ((m, lens) => over (lens, sort (comparator), m), m)
Now a good question is how much this abstraction buys us. Using the same range and diagonals functions, we could write sortMatrix like this:
const sortMatrix = (comparator) => (m) =>
diagonals (m)
.reduce (
(m, diagonal) => {
const vals = diagonal .map (([y, x]) => m [y] [x]) .sort (comparator)
return diagonal .reduce ((m, [y, x], i) => {m [y] [x] = vals [i]; return m}, m)
},
m .map (r => [...r])
)
which involves fewer lines of code than the combination of coordLens, diagLenses, and even our shortest earlier version of sortMatrix.
One argument is that it adds nothing, that this version is fine. If you have to do nothing else with those diagonals, or with other collections of coordinates, this might be true. But these lenses can be very convenient. If we wanted to total up each diagonal for some reason, it's a one-liner on top of the response from diagonalLenses:
const m = [
[1, 3, 9, 4],
[9, 5, 7, 7],
[3, 6, 9, 7],
[1, 2, 2, 2]
]
const myDiagonals = diagonalLenses (m .length, m [0] .length)
const diagonalSums = myDiagonals .map (d => sum (view2 (d, m)))
diagonalSums // => [1, 12, 17, 18, 18, 9, 2]
for an obvious sum function over an array.
And there are many more things we could do with them.
One thing that I should make clear is that these lenses we create are not specific to a particular matrix. Our list of diagonal lenses for one m x n matrix are exactly the same for another m x n one.
And the same is true for the underlying coordinate lenses. They have to do only with the shape of the matrix. We can easily imagine a sudoku solver which has a lens for each row, column, and box, which we then test for a correct solution with something like
const gridCompleted = (grid) =>
lenses .every (lens => completeGroup (view (lens, grid)))
Here we go:
function* enumerateDiagonals(xLength, yLength) {
for (let y = 0; y < yLength; y++) {
yield {
x: 0,
y: y
};
}
for (let x = 1; x < xLength; x++) {
yield {
x: x,
y: yLength - 1
};
}
}
function sliceMatrix(matrix, diagonal) {
const slice = [];
for (let y = diagonal.y, x = diagonal.x; y >=0 && x<matrix[y].length ; y--, x++) {
slice.push(matrix[y][x])
}
return slice
}
function emplaceIntoMatrix(slice, matrix, diagonal) {
for (let i=0; i < slice.length; i++) {
matrix[diagonal.y - i][diagonal.x + i] = slice[i];
}
}
const matrix =
[
[1, 3, 9, 4],
[9, 5, 7, 7],
[3, 6, 9, 7],
[1, 2, 2, 2]
];
const Ylength = matrix.length
const Xlength = matrix[0].length
console.log(Ylength)
console.log(Xlength)
const sortedMatrix = [ ];
for(let i=0; i<Ylength; i++) {
sortedMatrix[i] = new Array(Xlength);
}
for (const diagonal of enumerateDiagonals(Xlength, Ylength)) {
var slice = sliceMatrix(matrix, diagonal);
slice.sort();
emplaceIntoMatrix(slice, sortedMatrix, diagonal);
}
console.log(sortedMatrix);
const cols = matrix[0].length;
const rows = matrix.length;
const maxLength = Math.max(cols, rows);
let tempArr = [];
let result = [];
for (let k = 0; k <= 2 * (maxLength - 1); k++) {
let temp = [];
for (let y = cols - 1; y >= 0; y--) {
let x = k - y;
// console.log(k, y, x);
if (x >= 0 && x < rows) {
temp.push(matrix[y][x]);
}
}
if (temp.length > 0) {
// console.log(temp.sort());
tempArr.push(temp.sort());
}
}
for (let k = 0; k <= maxLength - 1; k++) {
let tempResult = [];
let arr = tempArr.filter((a) => a.length > 0);
// console.log(arr);
for (let i = 0; i <= maxLength - 1; i++) {
const length = arr[i].length;
tempResult.push(arr[i][length - 1]);
tempArr[tempArr.indexOf(arr[i])].pop();
}
result.push(tempResult);
}
return result;
I need to sum the numbers on the perimeter of this 2D array
const arr = [[1,5,3,4],
[4,9,9,7],
[3,8,7,4]];
The answer is 79 but i dont know how to write function.
You could visit all values and chgeck if the indices are either zero or the length of actual array minus one.
const
array = [[3, 8, 9, 7, 6], [6, 3, 8, 9, 7], [7, 6, 3, 8, 9]],
perimeter = array.reduce((sum, row, i, a) =>
row.reduce((s, v, j, b) =>
s + (i === 0 || j === 0 || i + 1 === a.length || j + 1 === b.length
? v
: 0,
sum)
),
0
);
console.log(perimeter);
This function will return all the perimeter numbers in a matrix, then flat and sum each item.
const arr = [[3, 8, 9, 7, 6], [6, 3, 8, 9, 7], [7, 6, 3, 8, 9]];
var snail = function(arr) {
let output = [];
output.push(arr[0]);
output.push(arr[arr.length - 1]);
for(let item of arr){
if(item != arr[0] && item != arr[arr.length - 1]){
output.push(item[0]);
output.push(item[item.length - 1]);
}
}
return output
}
const perimeter = snail(arr).flat(1);
const sum = perimeter.reduce((a, b) => a + b);
console.log(sum);
arr.map(ar => ar.reduce((a,b) => a + b, 0)).reduce((a,b) => a + b, 0)
I've gotten stuck on this practice problem in my software engineering bootcamp, and am hoping that someone can point me in the right direction.
Write a function generatePairs that accepts an integer and generates an array containing the pairs of integers [a, b]. The pairs should be sorted by increasing values of a then increasing values of b.
here are some examples of what should be returned for different inputs:
generatePairs(3) // [ [0, 0], [0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3] ]
generatePairs(2) // [ [0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2] ]
generatePairs(1) // [ [0, 0], [0, 1], [1,1]]
generatePairs(0) // [ [0, 0]]
and here is my code so far:
function generatePairs (num){
array = [];
// 0 [0,0] [0,1]
// 1
// 2
for (i = 0; i<=num; i++){
array.push([i,i]);
if ((i+1)<=num) {
array.push([i,i+1])
}
if ( num - i <= num && i===0 && num < i ) {
array.push([i,num])
if (num + i < i) {
array.pop();
}
}
}
return array;
}
generatePairs(2) // [ [0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2] ]
the issue I'm running into is that, for example, when I try it out with 2, I'm missing the [0,2] subarray. The methods I've tried to work around this have mostly consisted of additional if and else loops, but with each one I've tried I either end up with subarrays at the end that go higher than they should, or a semi-working system that would only work for 2 and not for any number that could be inputted into the function.
Isn't it much simpler than that?
function generatePairs(num) {
let arr = []
for (let i = 0; i <= num; i++) {
for (let j = i; j <= num; j++) {
arr.push([i, j])
}
}
return arr
}
console.log(generatePairs(2));
solution: (ninja code)
const generatePairs = n => Array.apply(null,{length:((n+1)*(n+2)/2)}).reduceRight((a,c,i)=>{
a.r.push([...a.p])
if(++a.p[1]>n) a.p[1]=++a.p[0]
return i?a:a.r
},{p:[0,0],r:[]})
for (let x=4;x--;) document.write(x,'->',JSON.stringify(generatePairs(x)), '<br>')
This is what you want right here. You loop through num for the first part until you get to num and for each first part loop from that first part to num.
function generatePairs(num) {
var output = []
for (var i = 0; i < num + 1; i++) {
for (var k = i; k < num + 1; k++) {
output.push([i, k])
}
}
return output
}
recursion
We can implement generatePairs in an wishful way -
const generatePairs = (n = 0) =>
chooseN(2, range(0, n))
range is a simple function that generates an array from a to b -
const range = (a = 0, b = 0) =>
a > b // base
? []
: [ a, ...range(a + 1, b) ] // inductive: a <= b
and chooseN is a generic that generates all n-sized samples from array a -
const chooseN = (n = 0, a = []) =>
n <= 0 // base
? [[]]
: a.length <= 0 // inductive: n > 0
? []
: chooseN(n - 1, a) // inductive: n > 0, non-empty a
.map(r => [a[0], ...r])
.concat(chooseN(n, a.slice(1)))
See generatePairs working in your own browser below -
const range = (a = 0, b = 0) =>
a > b
? []
: [ a, ...range(a + 1, b) ]
const chooseN = (n = 0, a = []) =>
n <= 0
? [[]]
: a.length <= 0
? []
: chooseN(n - 1, a)
.map(r => [a[0], ...r])
.concat(chooseN(n, a.slice(1)))
const generatePairs = (n = 0) =>
chooseN(2, range(0, n))
const log = x =>
console.log(JSON.stringify(x))
log(generatePairs(3))
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
log(generatePairs(2))
// [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]
log(generatePairs(1))
// [[0,0],[0,1],[1,1]]
log(generatePairs(0))
// [[0,0]]
generators
Because combinatorial problems typically involve big solution spaces, it's common to generate combinations lazily. In JavaScript, we can do this using generators -
const chooseN = function* (n = 0, a = [])
{ if (n <= 0)
return yield []
if (a.length <= 0)
return
for (const r of chooseN(n - 1, a))
yield [a[0], ...r]
yield* chooseN(n, a.slice(1))
}
Notice the structurally similarity between this program and the one above -
const chooseN = function* (n = 0, a = [])
{ if (n <= 0) // if (n <= 0)
return yield [] // return [[]]
if (a.length <= 0) // else if (a.length <= 0)
return // return []
// else return:
for (const r of chooseN(n - 1, a)) // chooseN(n - 1, a).map(r =>
yield [a[0], ...r] // [a[0],...r])
yield* chooseN(n, a.slice(1)) // .concat(chooseN(n, a.slice(1)))
}
For example, we could write a solver that finds the first pair, [ a, b ] where a > 3 and 3*a is equal to 2*b. Critically, no pairs will be generated after the first solution is found -
const solver = (size = 0) =>
{ for(const [a, b] of generatePairs(size))
if (a > 3)
if (3 * a === 2 * b)
return [a, b]
}
console.log(solver(10))
// [ 4, 6 ]
And the solution a = 4, b = 6 is correct: 4 > 3 is true and 3*4 is equal to 2*6 (12).
Below, we can generate the entire array of pairs, if we wish, using Array.from -
const allPairs =
Array.from(generatePairs(3)) // <-- Array.from exhausts an iterable
console.log(allPairs)
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
Expand the snippet below to generate pairs using JavaScript's generators -
const range = (a = 0, b = 0) =>
a > b
? []
: [ a, ...range(a + 1, b) ]
const chooseN = function* (n = 0, a = [])
{ if (n <= 0)
return yield []
if (a.length <= 0)
return
for (const r of chooseN(n - 1, a))
yield [a[0], ...r]
yield* chooseN(n, a.slice(1))
}
const generatePairs = (n = 0) =>
Array.from(chooseN(2, range(0, n)))
const log = x =>
console.log(JSON.stringify(x))
log(generatePairs(3))
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
log(generatePairs(2))
// [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]
log(generatePairs(1))
// [[0,0],[0,1],[1,1]]
log(generatePairs(0))
// [[0,0]]
I was trying to create an even number array of Fibonacci series using Functional Programming - below code
let a = [1, 2];
const r = (n) =>
Array.from(
a[a.length - 1] + a[a.length - 2] <= n ?
a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
a
)
.filter(v => !(v % 2))
//.reduce((s, v) => s+=v, 0)
console.log(r(56))
It is giving correct array but when I wanted to calculate the sum (using reduce method by commenting the last line) it is giving 0 as a result
let a = [1, 2];
const r = (n) =>
Array.from(
a[a.length - 1] + a[a.length - 2] <= n ?
a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
a
)
.filter(v => !(v % 2))
.reduce((s, v) => s+=v, 0)
console.log(r(56))
in Repl.it (Link - https://repl.it/#rahul4sap/1). However, when I try to paste the same in Chrome Dev tools it is giving correct output. Can someone please help me explain why different behavior in Chrome Dev tool and Repl.it (same behaviour I see in local Node server)
Also, it will be good if someone please help me in fixing this as well (Please note I wanted to solve this in as much Functional way as possible)
Thanks in advance!
You could separate the functions an dget the fibonacci array first and then filter the array, and so on.
This approach uses a recursion by handing over a new build array.
const
add = (a, b) => a + b,
f = (n, a = [1, 2]) => a[a.length - 1] + a[a.length - 2] < n
? f(n, [...a, a[a.length - 1] + a[a.length - 2]])
: a,
r = n => f(n)
.filter(v => !(v % 2))
.reduce(add, 0);
console.log(r(56));
Consider a simple recursive function, fibs -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
console.log(fibs(10)) // first 10 fib numbers
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
Now add your .filter -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
const evens =
fibs(10)
.filter(n => !(n & 1))
console.log(evens)
// [ 0, 2, 8, 34 ]
Now add your .reduce -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
const sumEvens =
fibs(10)
.filter(n => !(n & 1))
.reduce((r, n) => r + n, 0)
console.log(sumEvens)
// 44
To see how you can compute fibonacci using other functional programming techniques, see this recent Q&A
Thank you for this. But I am looking for pushing element in an array (probably in a single function) until certain condition is met (like create Fibbonacci array until the last element is less than 100).
You change n = 0 to until = 0 and change the exit condition of your loop from n <= 0 to a > until -
const fibs = (until = 0, a = 0, b = 1) =>
a > until
? []
: [ a, ...fibs(until, b, a + b) ]
console.log(fibs(100))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]
const sumEvens =
fibs(100)
.filter(n => !(n & 1))
.reduce((r, n) => r + n, 0)
console.log(sumEvens)
// 4
You may receive result in one line when you know how many fibonacci numbers do you need.
For example this code filter even numbers from the first 10 fibonacci numbers and calculate their sum:
let arr = (n) => [1, 2, ...Array(n-2)].reduce((acc, rec, idx) => (idx < 2) ? [...acc, rec] : [...acc, (acc[idx-2] + acc[idx-1])],[])
.filter(it => !(it % 2))
.reduce((s, v) => s+=v, 0)
console.log(arr(10))
I'm basically looking for a simpler way to do this:
heights.forEach((height, i) => {
var p = i > 0 ? i -1 : 0;
this.breakingPoints.push(height+heights[p])
})
If I input an array that is:
[0,2,5,5]
I would like to output
[0,2,7,12]
You could use map() method with closure to return new array.
const arr = [0,2,5,5];
const result = (s => arr.map(e => s += e))(0);
console.log(result)
You can simply store the variable to push in a variable which will allow you to automatically sum the new value to it without checking the index.
var total = 0;
heights.forEach(height => {
this.breakingPoints.push(total += height);
})
The result would be:
[0, 2, 7, 12]
You can use Array.reduce method.
let inputArray = [1, 2, 3, 4];
let outputArray = [];
inputArray.reduce(function(accumulator, currentValue, currentIndex) {
return outputArray[currentIndex] = accumulator + currentValue; }, 0);
You could use reduce and spread operator to concat values:
const input = [0, 2, 5, 5];
const output = input.reduce((acc, val) => [...acc, (acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val],[]);
Or when using < ES6
var output = input.reduce(function (acc, val) { return acc.concat([(acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val]); }, []);