Split Array of items into N Arrays - javascript

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

Related

Sum of similar value in n X n dimensional array with n^2 complexity

Given an array [[1, 7, 3, 8],[3, 2, 9, 4],[4, 3, 2, 1]],
how can I find the sum of its repeating elements? (In this case, the sum would be 10.)
Repeated values are - 1 two times, 3 three times, 2 two times, and 4 two times
So, 1 + 3 + 2 + 4 = 10
Need to solve this problem in the minimum time
There are multiple ways to solve this but time complexity is a major issue.
I try this with the recursion function
How can I optimize more
`
var uniqueArray = []
var sumArray = []
var sum = 0
function sumOfUniqueValue (num){
for(let i in num){
if(Array.isArray(num[i])){
sumOfUniqueValue(num[i])
}
else{
// if the first time any value will be there then push in a unique array
if(!uniqueArray.includes(num[i])){
uniqueArray.push(num[i])
}
// if the value repeats then check else condition
else{
// we will check that it is already added in sum or not
// so for record we will push the added value in sumArray so that it will added in sum only single time in case of the value repeat more then 2 times
if(!sumArray.includes(num[i])){
sumArray.push(num[i])
sum+=Number(num[i])
}
}
}
}
}
sumOfUniqueValue([[1, 7, 3, 8],[1, 2, 9, 4],[4, 3, 2, 7]])
console.log("Sum =",sum)
`
That's a real problem, I am just curious to solve this problem so that I can implement it in my project.
If you guys please mention the time it will take to complete in ms or ns then that would be really helpful, also how the solution will perform on big data set.
Thanks
I would probably use a hash table instead of an array search with .includes(x) instead...
And it's also possible to use a classical for loop instead of recursive to reduce call stack.
function sumOfUniqueValue2 (matrix) {
const matrixes = [matrix]
let sum = 0
let hashTable = {}
for (let i = 0; i < matrixes.length; i++) {
let matrix = matrixes[i]
for (let j = 0; j < matrix.length; j++) {
let x = matrix[j]
if (Array.isArray(x)) {
matrixes.push(x)
} else {
if (hashTable[x]) continue;
if (hashTable[x] === undefined) {
hashTable[x] = false;
continue;
}
hashTable[x] = true;
sum += x;
}
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
This is probably the fastest way...
But if i could choose a more cleaner solution that is easier to understand then i would have used flat + sort first, chances are that the built in javascript engine can optimize this routes instead of running in the javascript main thread.
function sumOfUniqueValue (matrix) {
const numbers = matrix.flat(Infinity).sort()
const len = numbers.length
let sum = 0
for (let i = 1; i < len; i++) {
if (numbers[i] === numbers[i - 1]) {
sum += numbers[i]
for (i++; i < len && numbers[i] === numbers[i - 1]; i++);
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
You could use an objkect for keeping trak of seen values, like
seen[value] = undefined // value is not seen before
seen[value] = false // value is not counted/seen once
seen[value] = true // value is counted/seen more than once
For getting a value, you could take two nested loops and visit every value.
Finally return sum.
const
sumOfUniqueValue = (values, seen = {}) => {
let sum = 0;
for (const value of values) {
if (Array.isArray(value)) {
sum += sumOfUniqueValue(value, seen);
continue;
}
if (seen[value]) continue;
if (seen[value] === undefined) {
seen[value] = false;
continue;
}
seen[value] = true;
sum += value;
}
return sum;
},
sum = sumOfUniqueValue([[1, 7, 3, 8], [3, 2, 9, 4], [4, 3, 2, 1]]);
console.log(sum);
Alternatively take a filter and sum the values. (it could be more performat with omitting same calls.)
const
data = [[1, 7, 3, 8], [3, 2, 9, 4, 2], [4, 3, 2, 1]],
sum = data
.flat(Infinity)
.filter((v, i, a) => a.indexOf(v) !== a.lastIndexOf(v) && i === a.indexOf(v))
.reduce((a, b) => a + b, 0);
console.log(sum);
You can flatten the array, filter-out single-instance values, and sum the result:
const data = [
[ 1, 7, 3, 8 ],
[ 3, 2, 9, 4 ],
[ 4, 3, 2, 1 ]
];
const numbers = new Set( data.flat(Infinity).filter(
(value, index, arr) => arr.lastIndexOf(value) != index)
);
const sum = [ ...numbers ].reduce((a, b) => a + b, 0);
Another approach could be the check the first and last index of the number in a flattened array, deciding whether or not it ought to be added to the overall sum:
let sum = 0;
const numbers = data.flat(Infinity);
for ( let i = 0; i < numbers.length; i++ ) {
const first = numbers.indexOf( numbers[ i ] );
const last = numbers.lastIndexOf( numbers[ i ] );
if ( i == first && i != last ) {
sum = sum + numbers[ i ];
}
}
// Sum of numbers in set
console.log( sum );

Javascript: Split an array according to a pattern: items 1, 5, 10, then 2, 6, 11, then 3, 7, 12

I am trying to split an array which has a repeating pattern of elements 1, 2, 3, and 4. I want to turn my array [1,2,3,4,5,6,7,8,9,10] into four arrays: [1,5,10], [2,6,11], [3,7,12], and [4,8,13]. I tried using multiples, but the result creates the new arrays in a wrong order. Here is my attempt:
var upload_names_and_ids = [
"Certificat de salaire", //first line is the upload's visible title
"certificat-de-salaire", //second line is the upload's id
"no-info-circle", //third line is the info-circle class
"", //fourth line is the info-circle text
"Allocations Familiales",
"alloc-familiales",
"no-info-circle",
"",
"Courrier Impot (déclaration précédente)",
"courrier-impot",
"info-circle right",
""
];
//Seperate our first array into 4
var upload_names = [];
var upload_ids = [];
var upload_info_circle_class = [];
var upload_info_circle_content = [];
for (var i=0; i<upload_names_and_ids.length; i++){
if (i%4==0) {
upload_info_circle_content.push(upload_names_and_ids[i]);
} else if (i%3==0) {
upload_info_circle_class.push(upload_names_and_ids[i]);
} else if (i%2==0) {
upload_names.push(upload_names_and_ids[i]);
} else {
upload_ids.push(upload_names_and_ids[i]);
}
}
Any help is much appreciated, thank you!
You could take a remainder with index and wanted length.
const
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
length = 4,
result = array.reduce(
(r, v, i) => (r[i % length].push(v), r),
Array.from({ length }, _ => [])
);
console.log(result);
If you like to use predeclared array directly, you could replace this line
Array.from({ length }, _ => [])
with
[upload_names, upload_ids, upload_info_circle_class, upload_info_circle_content]
where the accumulator of Array#reduce keeps the object references.
It's not i%3==0 (which matches 0, 3, 6, …) but i%4==1 (to match 1, 5, 10, …). Same for i%2==0.
I would add a helper sliceN that takes an array and a positive integer. Then returns an array of arrays where the inner arrays are of length n.
sliceN([1,2,3,4,5,6,7,8,9], 3) //=> [[1,2,3], [4,5,6], [7,8,9]]
sliceN([1,2,3,4,5,6], 2) //=> [[1,2], [3,4], [5,6]]
Then also add a helper transpose that transposes a matrix.
transpose([[1,2,3], [4,5,6], [7,8,9]]) //=> [[1,4,7], [2,5,8], [3,6,9]]
transpose([[1,2], [3,4], [5,6]]) //=> [[1,3,5], [2,4,6]]
With these two helpers you can create the wanted result with ease.
const upload_names_and_ids = [
"Certificat de salaire", //first line is the upload's visible title
"certificat-de-salaire", //second line is the upload's id
"no-info-circle", //third line is the info-circle class
"", //fourth line is the info-circle text
"Allocations Familiales",
"alloc-familiales",
"no-info-circle",
"",
"Courrier Impot (déclaration précédente)",
"courrier-impot",
"info-circle right",
""
];
const [
upload_names,
upload_ids,
upload_info_circle_class,
upload_info_circle_content,
] = transpose(sliceN(upload_names_and_ids, 4));
console.log(upload_names);
console.log(upload_ids);
console.log(upload_info_circle_class);
console.log(upload_info_circle_content);
function sliceN(array, n) {
const slices = [];
for (let i = 0; i < array.length; i += n) {
slices.push(array.slice(i, i + n));
}
return slices;
}
function transpose(rows) {
if (rows.length == 0) return [];
const columns = rows[0].map(cell => Array.of(cell));
for (let iRow = 1; iRow < rows.length; iRow += 1) {
for (let iCol = 0; iCol < columns.length; iCol += 1) {
columns[iCol].push(rows[iRow][iCol]);
}
}
return columns;
}
If you are already use a library with helper functions chances are that one or both of these data transforming methods are present. sliceN can often be found as something with split, slice or chunk in the name. transpose is very specific and if present will probably be present under the same name.
As an example Ramda offers both these methods.
R.transpose(R.splitEvery(4, upload_names_and_ids))

Way to multiply each element of one array to PARTS of another?

I am newbie in programming and try to find out how to multiply
[1,1,0]
to
[4,9,7,2,1,6]
for the next result output
[4,9,7,2,0,0]
As you see I want to multiply each value of [1,1,0] array to each two of second array by shifting in them
[1..] * [4,9..] = [4,9]
[.1.] * [.7,2.] = [7,2]
[..0] * [..1,6] = [0,0]
As example in js i writed something like
var firstArray = [1,1,0];
var secondArray = [4,9,7,2,1,6];
var shift = secondArray / firstArray;
var startpos = 0;
var outArray = [];
for(i=0; i< firstArray.length; i++){
for(z=i; z< shift+i; z++){
outArray.push(firstArray[i] * secondArray[z]);
}
}
console.log(outArray);
It may be in python
You can abuse zip and list slicing:
a = [1, 1, 0]
b = [4, 9, 7, 2, 1, 6]
shift = len(b) // len(a) # use / in Python 2
li = []
for num_a, num_b1, num_b2 in zip(a, b[::shift], b[1::shift]):
li.extend([num_a * num_b1, num_a * num_b2])
print(li)
# [4, 9, 7, 2, 0, 0]
You can express this as a standard matrix multiplication by making your inputs 2D arrays.
I got the multiplication algorithm from here: https://stackoverflow.com/a/27205510/5710637
The calculation would now look like:
[1,0,0] [4,9] [4,9]
[0,1,0] * [7,2] = [7,2]
[0,0,0] [1,6] [0,0]
function multiplyMatrices(m1, m2) {
var result = [];
for (var i = 0; i < m1.length; i++) {
result[i] = [];
for (var j = 0; j < m2[0].length; j++) {
var sum = 0;
for (var k = 0; k < m1[0].length; k++) {
sum += m1[i][k] * m2[k][j];
}
result[i][j] = sum;
}
}
return result;
}
var in1 = [[1, 0, 0], [0, 1, 0], [0, 0, 0]];
var in2 = [[4, 9], [7, 2], [1, 6]]
console.log(multiplyMatrices(in1, in2))
In Javascript, you could use a more functional approach by using
Array#reduce for iterating the factors and returning a new array,
Array#concat for adding a part result after multiplying to the result set,
Array#slice, for getting only two elements of the values array,
Array#map for multiplying the part array with the given factor,
at least use an array as start value for reduce.
var factors = [1, 1, 0],
values = [4, 9, 7, 2, 1, 6],
result = factors.reduce(
(r, f, i) => r.concat(
values
.slice(i * 2, (i + 1) * 2)
.map(v => f * v)
),
[]
);
console.log(result);
You can do this:
Iterate over first array so that you get a number to multiply.
Then extract two elements from the target array and multiply, store the result in res array.
var mul = [1,1,0];
var target = [4,9,7,2,1,6];
var start = 0;
var res = [];
mul.forEach(function(v,i) {
var arr = target.slice(start, start+2);//from start index extract two
//elements
arr.forEach(function(val,i) {
res.push(v * val);
});
start += 2;
});
console.log(res);
You can use map() on array2 and use one var for incrementing index of array1 for each two elements and then multiply current element of array1 with element from array2 that has index as that var.
var a1 = [1,1,0];
var a2 = [4,9,7,2,1,6];
var j = 0;
var result = a2.map(function(e, i) {
if(i % 2 == 0 && i != 0) j++
return e * a1[j];
})
console.log(result)
In python you can use the following code. I'm assuming the length of the second array is larger and it is divisible by the length of the shorter array
def multiply(a, b):
x, y = len(a), len(b) # Find lengths
assert x % y == 0
n = x / y
result = [a[i] * b[i / n] for i in range(x)] # For each index in a, calculate the appropriate element in output by multiplying with relevant part
print result

Find Missing Numbers from Unsorted Array

I found this JavaScript algorithm excercise:
Question:
From a unsorted array of numbers 1 to 100 excluding one number, how will you find that number?
The solution the author gives is:
function missingNumber(arr) {
var n = arr.length + 1,
sum = 0,
expectedSum = n * (n + 1) / 2;
for (var i = 0, len = arr.length; i < len; i++) {
sum += arr[i];
}
return expectedSum - sum;
}
I wanted to try and make it so you can find multiple missing numbers.
My solution:
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
function findMissingNumbers(arr) {
var missingNumbersCount;
var missingNumbers = [];
arr.sort(function(a, b) {
return a - b;
})
for(var i = 0; i < arr.length; i++) {
if(arr[i+1] - arr[i] != 1 && arr[i+1] != undefined) {
missingNumbersCount = arr[i+1] - arr[i] - 1;
for(j = 1; j <= missingNumbersCount; j++) {
missingNumbers.push(arr[i] + j)
}
}
}
return missingNumbers
}
findMissingNumbers(someArr) // [6, 8, 9, 11, 12, 13, 14]
Is there a better way to do this? It has to be JavaScript, since that's what I'm practicing.
You could use a sparse array with 1-values at indexes that correspond to values in the input array. Then you could create yet another array with all numbers (with same length as the sparse array), and retain only those values that correspond to an index with a 1-value in the sparse array.
This will run in O(n) time:
function findMissingNumbers(arr) {
// Create sparse array with a 1 at each index equal to a value in the input.
var sparse = arr.reduce((sparse, i) => (sparse[i]=1,sparse), []);
// Create array 0..highest number, and retain only those values for which
// the sparse array has nothing at that index (and eliminate the 0 value).
return [...sparse.keys()].filter(i => i && !sparse[i]);
}
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
var result = findMissingNumbers(someArr);
console.log(result);
NB: this requires EcmaScript2015 support.
The simplest solution to this problem
miss = (arr) => {
let missArr=[];
let l = Math.max(...arr);
let startsWithZero = arr.indexOf(0) > -1 ? 0 : 1;
for(i = startsWithZero; i < l; i++) {
if(arr.indexOf(i) < 0) {
missArr.push(i);
}
}
return missArr;
}
miss([3,4,1,2,6,8,12]);
Something like this will do what you want.
var X = [2, 5, 3, 1, 4, 7, 10, 15]; // Array of numbers
var N = Array.from(Array(Math.max.apply(Math, X)).keys()); //Generate number array using the largest int from X
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;}); //Return the difference
};
console.log(N.diff(X));
Option 1:
1. create a binary array
2. iterate over input array and for each element mark binary array true.
3. iterate over binary array and find out numbers of false.
Time complexity = O(N)
Space complexity = N
Option 2:
Sort input array O(nLogn)
iterate over sorted array and identify missing number a[i+1]-a[i] > 0
O(n)
total time complexity = O(nlogn) + O(n)
I think the best way to do this without any iterations for a single missing number would be to just use the sum approach.
const arr=[1-100];
let total=n*(n+1)/2;
let totalarray=array.reduce((t,i)=>t+i);
console.log(total-totalarray);
You can try this:
let missingNum= (n) => {
return n
.sort((a, b) => a - b)
.reduce((r, v, i, a) =>
(l => r.concat(Array.from({ length: v - l - 1 }, _ => ++l)))(a[i - 1]),
[]
)
}
console.log(missingNum([1,2,3,4,10]));
Solution to find missing numbers from unsorted array or array containing duplicate values.
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
var array1 = [1, 3, 4, 7, 9];
var n = array1.length;
var totalElements = array1.max(); // Total count including missing numbers. Can use max
var d = new Uint8Array(totalElements)
for(let i=0; i<n; i++){
d[array1[i]-1] = 1;
}
var outputArray = [];
for(let i=0; i<totalElements; i++) {
if(d[i] == 0) {
outputArray.push(i+1)
}
}
console.log(outputArray.toString());
My solution uses the same logic as trincot's answer
The time complexity is O(n)
const check_miss = (n) => {
let temp = Array(Math.max(...n)).fill(0);
n.forEach((item) => (temp[item] = 1));
const missing_items = temp
.map((item, index) => (item === 0 ? index : -1))
.filter((item) => item !== -1);
console.log(missing_items);
};
n = [5, 4, 2, 1, 10, 20, 0];
check_miss(n);

Random non-repeating number generation in javascript between two limits

Is there any method apart from array splicing that I can use to generate a random number between two numbers without repeating at all until all the numbers between those two numbers have been generated? Shuffling techniques or any other array methods apart from splicing would be extremely helpful.
First we use the fisherYates implementation (credit goes to #ChristopheD) and extend the array prototype to have a shuffle function available
function arrayShuffle () {
var i = this.length, j, temp;
if ( i === 0 ) return false;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
}
Array.prototype.shuffle =arrayShuffle;
var numbers = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.shuffle();
Now with the use of the pop method we get a number from our seed until it is empty
numbers.pop(); //returns a number
To make sure we have an array filled with numbers in the range of start and end we use a simple loop to create our seed.
var start = 1;
var end = 5;
var numbers = new Array();
for (var i = start; i <= end; i++) {
numbers.push(i);
}
here is a sample on jsfiddle
UPDATE: put fisherYates algo to shuffle more efficient
What I usually do when dealing with smaller arrays is sorting the array by random:
yourArray.sort(function() { return 0.5 - Math.random() });
Try this http://jsbin.com/imukuh/1/edit:
function randRange(min, max) {
var result = [];
for (var i=min; i<=max; i++) result.push(i);
return result.map(function(v){ return [Math.random(), v] })
.sort().map(function(v){ return v[1] });
}
console.log(randRange(1,5));
// [4, 3, 1, 5, 2]
// [3, 5, 2, 4, 1]
// [1, 5, 2, 3, 4]
// [3, 2, 5, 1, 4]
// ...

Categories

Resources