Split an Array with specific chunks size - javascript

For example I have a chunks array, this array has the sizes of individual chunks.
let example = [3,3]; // Chunks array
let auxarrayindex = [1,2,3,4,5,6]; // Array that I want to splice
let example2 = [3,2,3]; // Chunks array
let auxarrayindex2 = [1,2,3,4,5,6,7,8]; // Array that I want to splice
The result that I want is:
[1,2,3],[4,5,6] and the second [1,2,3],[4,5],[6,7,8]
This is my code:
for (let auxexample = 0; auxexample < example.length; auxexample++) {
finalauxarray.push(auxarrayindex.slice(0, example[auxexample]));
}
The result from my code is:
[1,2,3],[1,2,3] and the second [1,2,3],[1,2],[1,2,3]

The problem is that your slice always starts at the same index (0).
Use a variable (like i) that you increase as you take chunks:
let example = [3,2,3];
let auxarrayindex = [1,2,3,4,5,6,7,8];
let finalauxarray = [];
let i = 0;
for (let auxexample = 0; auxexample < example.length; auxexample++) {
finalauxarray.push(auxarrayindex.slice(i, i+=example[auxexample]));
}
console.log(finalauxarray);
You could also use map for your loop:
let example = [3,2,3];
let auxarrayindex = [1,2,3,4,5,6,7,8];
let i = 0;
let finalauxarray = example.map(size => auxarrayindex.slice(i, i+=size));
console.log(finalauxarray);

The problem is because of the slice parameters are wrong
You can learn more about how slice works on this link
https://www.w3schools.com/jsref/jsref_slice_array.asp
It takes as first parameter the starti g position and as last parameter the ending position which is not included in the result
You can aslo use splice for this as well
https://www.w3schools.com/jsref/jsref_splice.asp
Hope that helps

Working example using splice instead of slice as I think it offers a slightly cleaner API for this particular use-case:
let example = [3, 3];
let auxArrayIndex = [1, 2, 3, 4, 5, 6];
let example2 = [3, 2, 3];
let auxArrayIndex2 = [1, 2, 3, 4, 5, 6, 7, 8];
function getChunks(chunkSizes, array) {
let result = [];
for (let chunkSize of chunkSizes) {
result.push(array.splice(0, chunkSize));
}
return result;
}
let chunks = getChunks(example, auxArrayIndex);
let chunks2 = getChunks(example2, auxArrayIndex2);
console.log(chunks); // logs "[1,2,3], [4,5,6]"
console.log(chunks2); // logs "[1,2,3], [4,5], [6,7,8]"

Related

How to delete duplicate copies on mapping element counter?

I am trying to create a little project where I can count the number of elements in an array. This part I have already done. My question is how can I fix a counting problem? I'm using a mapping method to get my element occurrence counter, but I want to put the data into an array. The only way I know how is to take the data from the mapping with .get. They way I'm doing it is by using this first part here:
let winners = [1, 2, 3, 2];
let nullArray = [];
let mode = new Map([...new Set(winners)].map(
k => [k, winners.filter(t => t === k).length]
));
for (let n in winners) {
nullArray.push(mode.get(winners[n]));
console.log(nullArray);
}
However, this will *n push matches. Like, if you have l=[1,2,2], because l[1]=2, and l[2]=2, they will be pushed into the nullArray as 2, however, it will also push l[2] and l[1] as the values are different. If you have three matches, it would duplicate 3 times, and so on. To counter this, I tried making a detector that would calculate when the same numbers in the nullArray are from the same copy but in a different order. To do this, I used the code I have below (combined with the original code)
let winners = [1, 2, 3, 2];
let nullArray = [];
let mode = new Map([...new Set(winners)].map(
k => [k, winners.filter(t => t === k).length]
));
for (let n in winners) {
nullArray.push(mode.get(winners[n]));
console.log(nullArray);
}
for (let num in nullArray) {
for (let c in nullArray) {
if (nullArray[num] === nullArray[c] && winners[num] === winners[c]) {
nullArray.splice(num, 1);
}
console.log(nullArray);
}
}
However, whenever I try this, the specific output on this array is [2,2]. How could I make a general solution that will eliminate all duplicate copies, only leaving a single copy of the number count (which in the case of [1,2,3,2], I would want nullArray=[1,2,1] as an output)
You can do something like this.
If you don't care about the order, you can just do the following.
const remove_dup_and_count = (winners = [1, 2, 3, 2]) =>{
let map = {}
//count elements
for (let n in winners) {
const curr_val = winners[n]
//duplicate, so we increment count
if(curr_val in map) map[curr_val] += 1
//first seen, so we start at 1
else map[curr_val] = 1
}
//lets grab the array of all keys in map
const keys_arr = Object.keys(map)
let count_arr = []
for(let i of keys_arr){
count_arr.push(map[i])
}
return count_arr
}
console.log(remove_dup_and_count())
If you care about the order, this is your best bet:
const remove_dup_and_count = (winners = [1, 2, 3, 2]) =>{
let map = new Map()
//count elements
for (let n in winners) {
const curr_val = winners[n]
//duplicate, so we increment count
if(map.get(curr_val)) map.set(curr_val, map.get(curr_val) + 1)
//first seen, so we start at 1
else map.set(curr_val,1)
}
let count_arr = []
//lets grab the array of all keys in map
for (const [key, value] of map) {
count_arr.push(value)
}
return count_arr
}
console.log(remove_dup_and_count())
I think you can use .reduce() method and then retrieve how many times the value is repeated in array using map.values(); something like the following snippet:
const winners = [1, 2, 3, 2];
const mapWinners = winners.reduce((winnersAccumulator, singleWinner) => winnersAccumulator.set(singleWinner, (winnersAccumulator.get(singleWinner) || 0) + 1), new Map())
console.log([...mapWinners.values()])

Optimizing a function that returns all combinations of an array's elements

I am trying to optimize this function that I found online.
Example input: [1, 2, 3]
Example output: [[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
Here's the code:
const combinations = arr => {
let parentValue = [];
let cursor = 0;
for (const parentThis of arr) {
const value = [[parentThis]];
for (const thiss of parentValue) {
value.push(thiss.concat([parentThis]));
}
parentValue = parentValue.concat(value);
}
return parentValue;
};
(the variable names are weird because I'm running this as a MongoDB aggregation)
Running this 10k times on an array of 10 elements takes about 23 seconds. How can I make it run faster? I am open to some tradeoffs.
An obvious improvement I found is to decrease the amount of elements. Running it 10k times on an array of 9 elements takes 9 seconds.
I suspect another improvement would be to reject some outputs before they are generated (single-element combinations and the all-elements combination might not be too useful), but I can't figure out how to put this into code.
I tried to improve by removing the first iteration (supplying [arr[0]] as the initialValue and starting the outer for loop from the second element) but it doesn't seem to make a significant difference.
About 1 second for 10k times on an array of 10 elements.
function powerset(A){
const n = A.length;
const numSets = (1 << n) - 1;
const result = new Array(numSets);
for (let k=1; k<=numSets; k++){
const set = [];
result[k - 1] = set;
let temp = k;
let i = 0;
while (temp){
if (temp & 1)
set.push(A[i]);
temp >>= 1;
i += 1;
}
}
return result;
}
var A = [1,2,3,4,5,6,7,8,9,10];
var start = new Date;
for (let i=0; i<10000; i++)
var t = powerset(A);
console.log((new Date - start) / 1000);
As noted by georg in the comments under this answer, the line, const result = new Array(numSets); can be replaced with const result = []; and the assignment to result.push(set); in order to possibly see further improvement in efficiency. (Tested on node with array size 15-20.)
Maybe a simple push could speed the code a bit.
// parentValue = parentValue.concat(value);
parentValue.push(...value);

How can I iterate & match the values from two different sized arrays until the longer array has been exhausted?

Say I have two arrays with the following values:
let array1 = (1,2,3,4);
let array2 = (1,2,3,4,5,6,7,8);
How do I exhaustively assign the values from array2 so that all of them are assigned to a key from array1; like so:
let result = (
1: {1,5},
2: {2,6},
3: {3,7},
4: {4,8},
);
If there were 9 values in array 2 then it would continue looping until:
let result = (
1: {1,5,9},
2: {2,6},
3: {3,7},
4: {4,8},
);
In my real-world example, array1 will be minutes, so {1..60}, array2 will be an unknown number of dates (more than 60). I want to continue assigning the unknown number of dates a key until all dates are assigned a minute key from 1-60.
Unless I misunderstand your question, one way to accomplish this is to implement array1 as a simple 2D array: an array of arrays.
let array1 = [[1],[2],[3],[4]];
let array2 = [1,2,3,4,5,6,7,8,9];
let row = 0;
let column = 0;
for (count = 0; count < array2.length; count++) {
if (row >= array1.length) {
row = 0;
column++;
}
array1[row][column] = array2[count];
row++;
}
consol.log(array1);
Try this quickly by going to the url "about:blank" and then right click somewhere and click inspect. Go to the console tab and paste the code above and press enter. Click the arrow from the output to expand the array and you should find that it worked as required. Also, not that it matters in your case, but this method of using the >= comparison instead of using % is faster for the task.
Try this:
let array1 = [1, 2, 3, 4];
let array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let result = [];
for(let i=0; i<array1.length; i++) {
result[i] = [];
for(let j=i; j<array2.length; j=j+array1.length) {
result[i].push(array2[j]);
}
}
console.log(result);

Best way to concatenate an array prefix and an array reversed prefix

Given two arrays and two indices, I need to concatenate the prefix of the first array and the reversed prefix of the second array.
For example:
// Input
arr1 = [1,2,3,4,5,6,7,8,9];
arr2 = [10,11,12,13,14,15];
ind1 = 6;
ind2 = 3;
// Output
arr = [1,2,3,4,5,6,12,11,10];
Here is my code:
function Concat(arr1,arr2,ind1,ind2) {
let arr = [];
for (let n = 0; n < ind1; n++)
arr.push(arr1[n]);
for (let n = ind2; n > 0; n--)
arr.push(arr2[n-1]);
return arr;
}
I am looking for a better (cleaner / faster / simpler / more elegant) way to do this. What can I try?
You can try something like this:
Note: This will not be faster than current approach. This is just little cleaner.
function Concat(arr1,arr2,ind1,ind2) {
return [].concat(arr1.slice(0, ind1), arr2.slice(0, ind2).reverse());
}
arr1 = [1,2,3,4,5,6,7,8,9];
arr2 = [10,11,12,13,14,15];
ind1 = 6;
ind2 = 3;
console.log(Concat(arr1, arr2, ind1, ind2))
As suggested, there will not be huge performance impact. You can check the difference js-perf sample.
An alternate approach if you have ability to override input structure.
Since we are expecting array of object in custom order, it will be easy to make it generic. Assuming the structure to be:
Please mind the syntax as I'm heavily working on Typescript, it is easier for me to write in that syntax.
interface ConcatObject {
value: Array<any>;
endIndex: number;
isReverse: boolean
}
when you read, it makes code easier to read and simpler to make it generic.
function Concat(arr) {
return arr.reduce(function(acc, cur) {
var temp = cur.value.slice(0, cur.endIndex);
if (cur.isReverse) {
temp = temp.reverse();
}
return acc.concat(temp);
}, []);
}
var data = [{
value: [1, 2, 3, 4, 5, 6, 7, 8, 9],
endIndex: 6
},
{
value: [10, 11, 12, 13, 14, 15],
endIndex: 3,
isReverse: true
}
]
console.log(Concat(data))
If ES6 is not a problem, you can do it by the code below:
var arr1 = [1,2,3,4,5,6,7,8,9];
var arr2 = [10,11,12,13,14,15];
var ind1 = 6;
var ind2 = 3;
var output = [...arr1.slice(0, ind1), ...arr2.slice(0, ind2).reverse()];
console.log(output);
If you don't want to use ES6 spread syntax, you can use array.prototype.concat :
var arr1 = [1,2,3,4,5,6,7,8,9];
var arr2 = [10,11,12,13,14,15];
var ind1 = 6;
var ind2 = 3;
var output = arr1.slice(0, ind1).concat(arr2.slice(0, ind2).reverse());
console.log(output);
Simplest solution
Code:
// declarations
arr1 = [1,2,3,4,5,6,7,8,9];
arr2 = [10,11,12,13,14,15];
ind1 = 6;
ind2 = 3;
var arr = [];
// changing length as per index
arr1.length = ind1;
arr2.length = ind2;
// reverse and concat to array
arr = arr1.concat(arr2.reverse());
console.log(arr);
Clean, Fast and efficient.
Using es6
let arr1 = [1,2,3,4,5,6,7,8,9],
arr2 = [10,11,12,13,14,15];
let ind1 = 6,
ind2 = 3;
let newArr = [...arr1.slice(0, ind1), ...arr2.slice(0, ind2).reverse()];
console.log(newArr)
If you want to concat many arrays you can look at this solution. This lets you to concat how many arrays you want and in which order using function cascading. You can continue this cascading and use optional parameter for reverse order.
const arr1 = [1,2,3,4,5,6,7,8,9];
const arr2 = [10,11,12,13,14,15];
const obj = {
items: [],
concat(arr, index, isReverse = false) {
let temp = arr.slice(0, index);
this.items = this.items.concat(isReverse ? temp.reverse() : temp);
return this;
}
};
obj.concat(arr1, 6).concat(arr2, 3, true);
console.log(obj.items);

Create an array using longest length of arrays passed to a function, using Math.max?

I am trying to build a new array with a length that is equal to the longest array that is passed to a function. There can be an infinite number of arrays passed to the function, which is why I am trying to use Math.max.
I worked this up that uses loops...:
function sumInternalValues() {
let arrays = Array.from(arguments);
let longest = 0;
arrays.forEach(arr => {
longest = (arr.length > longest) ? arr.length : longest;
})
let newArr = new Array(longest);
//... do other things but for sake of this question, return here now
return newArr.length;
}
let arr1 = [1, 2, 3, 4];
let arr2 = [5, 6, 7, 8, 9, 10];
console.log(sumInternalValues(arr1, arr2));
But how can I get Math.max to work with this instead?
function sumInternalValues() {
let newArr = new Array(Math.max.apply(Math, arguments.length?));
}
Note: I will be answering my own question based on the guidelines here. I spent a fair amount of time trying to get this and didn't find much support on SO.
You can do this by capturing the arguments as an array using array.from(), and then mapping the resulting array to get just lengths. And then apply that array to the Math.max function:
function sumInternalValues() {
let args = Array.from(arguments);
let newArr = new Array(Math.max.apply(Math, args.map(a => a.length)));
// ... do some other things, but for the sake of this question, return here
return newArr.length
}
let arr1 = [1, 2, 3, 4];
let arr2 = [5, 6, 7, 8, 9, 10];
console.log(sumInternalValues(arr1, arr2));
A dense array:
let denseArr = Object.assign([], arr1, arr2).fill(undefined);
A sparse array:
let sparseArr = [];
sparseArr.length = Math.max(...[arr1, arr2].map(arr => arr.length));

Categories

Resources