javascript map and reduce array list - javascript

I have a list of array in this format
data = [[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]]
I want the output in this format
[[11/1, 12/2,13/3,14/4,15/5,16/6,17/7,18/8,19/9,20/10],
[21/11,22/12,23/13,24/14,25/15,26/16,27/17,28/18,29/19,30/20]]
I have used for loop and this is how it looks
const totalData = data.length;
for(var i =0 ; i < totalData ; i++){
for(var j =0; j < data[i].length; j++){
console.log(data[i+1][j]/data[i][j]);
}
}
I want to convert this using javascript map and reduce? is there any possible ways?
Thank you

for loops aren't bad practice, they just don't fit in a functional style of programming. The following solution presupposes that the arrays' lengths are equal:
const data = [
[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]
];
const result = data.map((arr, index) => {
const next = data[index + 1];
if (!Array.isArray(next)) {
return;
}
return arr.map((item, i) => next[i] / item);
}).filter(Boolean);
console.log(result);
I am sure you can figure out what to do if the arrays' lengths are not equal.

You could use a single reduce and map the items for a new array.
var data = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]],
result = [];
data.reduce((a, b) => (result.push(a.map((c, i) => b[i] / c)), b));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You need to create separated functions for each task:
/**
* Combine 2 arrays
* #param Array a
* #param Array b
*/
function combineArrays(a, b) {
var combined = [];
for (var i = 0; i < a.length; i++)
combined.push(a[i] / b[i]);
return combined;
}
/**
* Combine an group of arrays
* #param Array group
*/
function combineGroup(group) {
var newGroup = [];
for (var i = 0; i < group.length - 1; i++)
newGroup.push(combineArrays(group[i], group[i + 1]));
return newGroup;
}
The first function combine 2 arrays only.
The second function combine many arrays and return what you want.

if the lengths are not equal, the items in the tail of the longer one are ignored.
data = [
[1,2,3,4,5,6,7,8,9,10],
[11,12,13,14,15,16,17,18,19,20],
[21,22,23,24,25,26,27,28,29,30]
];
result = data.reduce((acc,current,i)=>{
var ret;
if(data[i].length <= data[i-1].length)
ret = data[i].map((item,j)=>(item / data[i-1][j]));
else
ret = data[i-1].map((item,j)=>(data[i][j] / item));
if(i==1)
return [ret]
else
return acc.concat([ret])
})
console.log(result)

Related

How to filter an array of numbers and take certain intervals?

I have this type of array.
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
Requirements to filter the array are
Omit every 4 items
Take the following 4 items
And continue until the end of the array.
At the end It should return [5,6,7,8,13,14,15,16,21,22,23,24]
const values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
newValues = values.filter((v, i) => i % 8 > 3)
console.log(newValues)
You could slice the chunks and add to the result array.
const
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
result = [];
let i = 0;
while (i < data.length) result.push(...data.slice(i += 4, i += 4));
console.log(...result);
You can create a partitioning function for achieving your result.
const arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
/**
* Pertition the array and create a new array.
*
* #param {array} arr The array to pertition.
* #param {number} skip The number of elements to skip
* #param {number} take Take the number of elements need to take after skipping.
*
* #return {array} The resulting array after pertition.
*/
const arrayAfterPertition = (arr, skip, take) => {
const length = arr.length;
let ans = [];
/** If there are not enough elements to skip then returns empty array */
if (length <= skip) return [];
let takeIndex = skip;
while (takeIndex < length) {
ans = [...ans, ...arr.slice(takeIndex, takeIndex + take)];
takeIndex = takeIndex + take + skip;
}
return ans;
}
console.log(JSON.stringify(arrayAfterPertition(arr, 4, 4)));
.as-console-wrapper {min-height: 100%!important; top: 0}
Lodash if you don't mind. Using Loash#chunk
const nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
const chunkSize = 4;
const result = _.chunk(nums, chunkSize)
.filter((v,i) => i % 2 ===1)
.flat();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdn.jsdelivr.net/lodash/4.10.0/lodash.js"></script>

Create Possible Combination in javascript/typescript/nodejs

let input = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
and i want output should be:
output = {
first: [[1,2], [3,4], [5,6], [7,8], [9,10]],
second: [[1,3], [2,4], [5,7], [6,9], [8,10]],
third: [[1,4], [2,3], [5,8], [7,9], [6,10]],
fourth: [[1,5], [2,6], [3,7], [8,9], [4,10]],
fifth: [[1,6], [2,8], [3,5], [4,9], [7,10]],
sixth: [[1,7], [2,9], [3,6], [4,8], [5,10]],
seventh: [[1,8], [2,7], [4,6], [5,9], [3,10]],
eighth: [[1,9], [3,8], [4,5], [6,7], [2,10]],
ninth: [[1,10], [2,5], [3,9], [4,7], [6,8]],
}
I need to write a code in javascript / typescript / nodejs by which i can put number ranges and will get a combinations of given numbers**( n-1 ), i want a code to be written which can return us **all possible combination and the combination will never conflict with other combinations.
Thanks in advance.
You could take a brute force approach with a recursive function for collected pairs and a list of available pairs.
If a new pair is possible to get, take this pair and call the function again.
function getAllPairs(array) {
var pairs = [];
for (let i = 0; i < array.length - 1; i++) {
for (let j = i + 1; j < array.length; j++) {
pairs.push([array[i], array[j]]);
}
}
return pairs;
}
function fill(pairs, result = []) {
function check(array) {
return array.every((s => a => a.every(v => !s.has(v) && s.add(v)))(new Set));
}
if (!pairs.length) return result;
var left = result.slice(Math.floor(result.length / half) * half);
for (let i = 0; i < pairs.length; i++) {
if (!check([...left, pairs[i]])) continue;
var newResult = fill([...pairs.slice(0, i), ...pairs.slice(i + 1)], [...result, pairs[i]]);
if (newResult) return newResult; // i miss something like returnIf
}
}
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
half = data.length / 2,
temp = fill(getAllPairs(data)),
result = [],
i = 0;
while (i < temp.length) result.push(temp.slice(i, i += half));
result.forEach(a => console.log(...a.map(a => a.map(v => v.toString().padStart(2, ' ')).join('|'))));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Why result of the function call is undefined?

Why array can't be displayed immediately after swap function call in JS? Why result of the function call is undefined?
const swap = (arr) => {
for (let i = 0; i < arr.length - 1; i++) {
var tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
r = [...Array(10)].map( (_, i) => (i + 1) * 3);
console.log(r); // --> Array [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30 ]
//swap(r);
// why array can't be displayed immediately after swap function call?
console.log( swap(r) ); // --> displays undefined but the swap function worked out
console.log(r); // --> Array [ 6, 9, 12, 15, 18, 21, 24, 27, 30, 3 ]
I think it's because the swap function returns nothing but I'm not sure. But
swap(r);
console.log(r);
works fine.
You don't need to return anything and leave your function swap as it. The passed array is a reference of r = [...Array(10)].map((_, i) => (i + 1) * 3) so, every modification will modify that array after the function swap ends.
Just print the array console.log(r);.
const swap = (arr) => {
for (let i = 0; i < arr.length - 1; i++) {
var tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
r = [...Array(10)].map((_, i) => (i + 1) * 3);
console.log(r); // --> Array [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30 ]
swap(r);
// why array can't be displayed immediately after swap function call?
// console.log(swap(r)); // --> displays undefined but the swap function worked out
console.log(r); // --> Array [ 6, 9, 12, 15, 18, 21, 24, 27, 30, 3 ]
.as-console-wrapper { max-height: 100% !important; top: 0; }
Yes you are correct, it's because you are trying to output the result of the swap function call but you are not returning anything specific. So the default result is undefined.
If you want to output the array after the swap, then return that in your function like so:
const swap = (arr) => {
for (let i = 0; i < arr.length - 1; i++) {
var tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
return arr;
}
r = [...Array(10)].map((_, i) => (i + 1) * 3);
console.log(swap(r));
Ultimately it is up to you to decide how you want the function to work. As you have identified there is no need to return anything at all as long as you don't try and use the result of the function call.
With regards to why it doesn't automatically return the array, well you have to remember that a function can do lots of different things to many objects. There would be no way to know which object or value should automatically be returned, so it doesn't make sense for it to try and do anything magic like that. If you want something returned, then make sure you return it.
Yes you are right; you should use return arr; but I think what you want is rotating the array.
arr = new Array(10).fill().map( (_, i) => (i + 1) * 3);
console.log(arr);
res = [...arr.slice(1),arr[0]]; // prettier but can be dramatically slow on large arrays
// or for even faster one :
rotate = (arr) => !(arr.push(arr.shift())) || arr;
// or
/*const rotate = (arr) => {
var first = arr[0];
for(var c = 0, l = arr.length - 1; c < l;)
arr[c] = arr[++c];
arr[arr.length-1] = first;
return arr;
}*/
console.log(res);
console.log(rotate(arr));

How to split a large array into smaller array based upon given index values,

I have a large array e.g. aa=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
I have another array which holds the indexes values based upon which large array need to be chunked. e.g. cc=[10,16]
I want that array aa to be chunked into new arrays
dd[] = [from 0 to cc[0]index]
ee[] = [from cc[0]index to cc[next value]index]
EXAMPLE
dd[] = [1,2,3,4,5,6,7,8,9,10]
ee[] = [11,12,13,14,15,16]
and so on until cc[] has indexes
I could not figure out the logic, if anyone can help me please.
You could use Array#map and Array#slice for the parts.
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
indices = [10, 16],
result = indices.map(function (a, i, aa) {
return array.slice(aa[i - 1] || 0, a);
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
you can use the new and simple array.slice:
var array=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
console.info(temparray);
}
You can do something like this if you don't wanna use build in methods.
function createChunks(aa, cc) {
var temp = [], chunks = [];
for(var i=0, j=0, k=0; i<aa.length; i++) {
if(aa[i] == cc[j]) {
temp[k] = aa[i];
chunks.push(temp);
temp = []; k=0; j++;
}
else
temp[k++] = aa[i];
}
return chunks;
}
var aa=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], cc=[10, 16];
var chunks = createChunks(aa, cc);
console.log(JSON.stringify(chunks));

Split Array of items into N Arrays

I want to split an Array of numbers into N groups, which must be ordered from larger to smaller groups.
For example, in the below code, split an Array of 12 numbers into 5 Arrays, and the result should be evenly split, from large (group) to small:
source: [1,2,3,4,5,6,7,8,9,10,11,12]
⬇
output: [1,2,3] [4,5,6] [7,8] [9,10] [11,12]
Playground
// set up known variables
var arr = [1,2,3,4,5,6,7,8,9,10,11,12],
numberOfGroups = 5,
groups = [];
// split array into groups of arrays
for(i=0; i<arr.length; i++) {
var groupIdx = Math.floor( i/(arr.length/numberOfGroups) );
// if group array isn't defined, create it
if( !groups[groupIdx] )
groups[groupIdx] = [];
// add arr value to group
groups[groupIdx].push( arr[i] )
}
// Print result
console.log( "data: ", arr );
console.log( "groups: ", groups )
Update:
Thanks to SimpleJ's answer, I could finish my work.
The use case for this is an algorithm which splits HTML lists into "chunked" lists, a think which cannot be easily achieved by using CSS Columns.
Demo page
I'm not 100% sure how this should work on different sized arrays with different group counts, but this works for your 12 digit example:
function chunkArray(arr, chunkCount) {
const chunks = [];
while(arr.length) {
const chunkSize = Math.ceil(arr.length / chunkCount--);
const chunk = arr.slice(0, chunkSize);
chunks.push(chunk);
arr = arr.slice(chunkSize);
}
return chunks;
}
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
console.log( chunkArray(arr, 5) )
A shorter version of #SimpleJ answer and without using slice two times.
function splitArrayEvenly(array, n) {
array = array.slice();
let result = [];
while (array.length) {
result.push(array.splice(0, Math.ceil(array.length / n--)));
}
return result;
}
console.log(splitArrayEvenly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 5))
I think this is a more of a mathematical problem than a Javascript.
const getGroups = (arr, noOfGroups) => {
const division = Math.floor(arr.length / numberOfGroups);
const groups = [[]];
let remainder = arr.length % numberOfGroups;
let arrIndex = 0;
for (let i = 0; i < noOfGroups; i++) {
for (let j = division + (!!remainder * 1); j >= 0; j--) {
groups[i].push(arr[arrIndex]);
arrIndex += 1;
}
remainder -= 1;
}
return groups;
};
const myGroups = getGroups([1,2,3,4,5,6,7,8,9,10,11,12], 5);
myGroups will be [[1, 2, 3], [4, 5, 6], [7, 8], [9, 10], [11, 12]]
This will work for any number of groups and players

Categories

Resources