split chunk array from bigger array - javascript

i have an array like this
const arr = [1,2,3,4,5,6,7];
i am trying to make sub arrays from this main array so that it will look something like this
const splitArray = [[1,4], [2,5], [3,6], [7]];
what i have tried so far is
const convertToSubArray = (array, chunkSize = 2) => {
let i, j, accum = [];
for (i=0, j=array.length; i<j; i+=chunkSize) {
accum = [...accum, array.slice(i, i+chunkSize)];
}
return accum;
}
But getting this as the output
[
[
1,
2
],
[
3,
4
],
[
5,
6
],
[
7
]
]
How can i achieve this, any help is appreciated

You could take a group of six items as offset and inside of each group of six take another offset build by the half of items (p) in this group.
p indices grouping comment
--- ------------- -------------------------- --------------
3 0 1 2 3 4 5 [[0, 3], [1, 4], [2, 5]]
3 0 1 2 3 4 [[0, 3], [1, 4], [2]]
2 0 1 2 3 [[0, 2], [1, 3]]
2 0 1 2 [[0, 1, 2]] special case
1 0 1 [[0, 1]] "
1 0 [[0]] "
At iterating check if the last index in the group is odd, then take a a single value instead of a pair of values.
const
chunk = array => {
const result = [];
for (let offset = 0; offset < array.length; offset += 6) {
const l = Math.min(array.length - offset, 6);
if (l <= 3) {
result.push(array.slice(offset, offset + 3));
break;
}
for (let i = 0, p = Math.ceil(l / 2); i < p; i++) {
result.push(i + 1 === p && l & 1
? [array[offset + i]]
: [array[offset + i], array[offset + i + p]]
);
}
}
return result;
};
console.log(chunk([1]));
console.log(chunk([1, 2]));
console.log(chunk([1, 2, 3]));
console.log(chunk([1, 2, 3, 4]));
console.log(chunk([1, 2, 3, 4, 5]));
console.log(chunk([1, 2, 3, 4, 5, 6]));
console.log(chunk([1, 2, 3, 4, 5, 6, 7]));
console.log(chunk([1, 2, 3, 4, 5, 6, 7, 8]));
console.log(chunk([1, 2, 3, 4, 5, 6, 7, 8, 9]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

const arr = [1, 2, 3, 4, 5, 6, 7]
const splitArray = [];
for (i = 0; i < arr.length; i++) {
if (arr[i + 3] != undefined) {
splitArray.push([arr[i], arr[i + 3]])
}
}
console.log(splitArray);

Related

How to convert the below array [duplicate]

I have an array like so: [1, 2, 3, 4, 5, 6, 7, 9, 10]. I need to chunk it into different size chunks, yet with a simple pattern of: 4, 3, 3, 3, 4, 3, 3, 3 like so:
[
[ // four
1,
2,
3,
4
],
[ // three (1/3)
5,
6,
7
],
[ // three (2/3)
8,
9,
10
],
[ // three (3/3)
11,
12,
13
],
[ // four
14,
15,
16,
17
],
[ // three (1/3)
18,
19,
20
], // and so on..
]
I have tried with this code I have customized:
const arr; // my array of values
const chuncked = arr.reduce((acc, product, i) => {
if (i % 3) {
return acc;
} else if (!didFourWayReduce) {
didFourWayReduce = true;
fourWayReduces++;
if ((fourWayReduces - 1) % 2) { // only make every second a "4 row"
return [...acc, arr.slice(i, i + 3)];
} else {
return [...acc, arr.slice(i, i + 4)];
}
} else {
didFourWayReduce = false;
return [...acc, arr.slice(i, i + 3)];
}
}, []);
And it works, almost, expect that the first chunk of threes (1/3) have the last element of the chunk with 4. So 1 key is repeated every first chunk of three. Like so:
[
[
1,
2,
3,
4
],
[
4, // this one is repeated, and it shouldn't be
5,
6
]
]
You could take two indices, one for the data array and one for sizes. Then slice the array with a given length and push the chunk to the chunks array.
Proceed until end of data.
var data = Array.from({ length: 26 }, (_, i) => i + 1),
sizes = [4, 3, 3, 3],
i = 0,
j = 0,
chunks = [];
while (i < data.length) chunks.push(data.slice(i, i += sizes[j++ % sizes.length]));
console.log(chunks);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const arr = Array.from({ length: 100 }, (_, i) => i);
const copy = [...arr];
const sizes = [4, 3, 3, 3];
const result = [];
let i = 0;
while (i <= arr.length && copy.length) {
result.push(copy.splice(0, sizes[i % sizes.length]));
i++;
}
console.log(result);
A recursive approach is fairly elegant:
const chunks = (xs, [s, ...ss]) =>
xs.length ? [xs .slice (0, s), ... chunks (xs .slice (s), [...ss, s])] : []
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
const sizes = [4, 3, 3, 3]
console .log (chunks (data, sizes))
.as-console-wrapper { max-height: 100% !important; top: 0; }
By replacing [s, ...ss] with [...ss, s], we pass a cycled version of the sizes array, so that for instance, [4, 3, 3, 3] becomes [3, 3, 3, 4]. This makes it easy to parse step-by-step.
Mod operator to check if it should be 4 or 3. Use two arrays just to make it easier (can be done with one)
const groupIt = arr => arr.reduce(({
group,
out
}, v, i) => {
var max = out.length % 4 === 0 ? 4 : 3
group.push(v)
if (group.length === max || i === arr.length - 1) {
out.push(group)
group = []
}
return {
group,
out
}
}, {
group: [],
out: []
}).out
console.log(groupIt([1, 2, 3, 4, 5, 6, 7, 8]))
var test = (new Array(30)).fill(0).map((x,i) => i + 1)
console.log(groupIt(test))
with just one:
const groupIt = arr => arr.reduce((out, v, i) => {
var max = (out.length - 1) % 4 === 0 ? 4 : 3
out[out.length - 1].push(v)
if (out[out.length - 1].length === max) {
out.push([])
}
return out
}, [[]])
console.log(groupIt([1, 2, 3, 4, 5, 6, 7, 8]))
var test = (new Array(30)).fill(0).map((x, i) => i + 1)
console.log(groupIt(test))
This answer is similar to that of Nina Scholz, but uses a for loop, which I personally find more clear.
const arr = Array.from({length: 100}, (_, i) => i + 1);
const sizes = [4, 3, 3, 3];
const result = [];
for (let i = 0, j = 0; i < arr.length; i += sizes[j], j = (j + 1) % sizes.length) {
result.push(arr.slice(i, i + sizes[j]));
}
console.log(result);

picking a unique set from an array of arrays

I attempted to ask a more complicated of this before but I couldn't explain it well so I am trying again with a simplified use case.
I will have an array of arrays like the following
var allData = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
I need to select 1 element from each array so that I get a unique set like [2,4,1,3,5] easy to do in this case as each array has all values. However this will rarely be the case. Instead I may have
var allData = [[1,2,4],[1,2],[1,2],[2,4,5],[1,2,3,5]]
In this case I couldn't pick 1 or 2 from the first array as that would prevent the 2nd and 3rd from having a unique combination. So something like [4,2,1,5,3] or [4,1,2,5,3] would be the only two possible answers for this combination.
The only way I see to do this is to just go through every combination but these will get fairly large so it doesn't seem reasonable as this happens real time. There are going to be at least 7 arrays, possibly 14 and distantly possible to have 31 so going through every combination would be fairly rough.
The 2nd part is if there is some way to "know" you have the best possible option. Say if there was some way I would know that having a single duplicate is my best case scenario. Even if I have to brute force it if I encounter a 1 duplication solution I would know to stop.
One easy way to get a very simple of this is to just subtract the number of possible choices from the number of elements but this is the correct answer in only the simplest of cases. Is there some type of library or anything to help solve these types of problems? It is a bit beyond my math abilities.
Here is something I have tried but it is too slow for larger sets and can fail. It works sometimes for the 2nd case I presented but only on luck
const allData = [[1,2,4],[1,2],[1,2],[2,4,5],[1,2,3,5]]
var selectedData = []
for (var i in allData){
console.log("length",allData[i].length)
var j = 0
while(j < allData[i].length){
console.log("chekcing",allData[i][j])
if (selectedData.includes(allData[i][j])){
console.log("removing item")
allData[i].splice(j,1)
}
else{j++}
}
var uniqueIds = Object.keys(allData[i])
console.log(uniqueIds)
var randId = Math.floor(Math.random() * uniqueIds.length)
console.log(randId)
selectedData.push(allData[i][randId])
console.log("selectedData",selectedData)
}
You can start with a fairly simple backtracking algorithm:
function pick(bins, n = 0, res = {}) {
if (n === bins.length) {
return res
}
for (let x of bins[n]) {
if (!res[x]) {
res[x] = n + 1
let found = pick(bins, n + 1, res)
if (found)
return found
res[x] = 0
}
}
}
//
let a = [[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 4]]
console.log(pick(a))
This returns a mapping item => bin index + 1, which is easy to convert back to an array if needed.
This should perform relatively well for N < 10, for more/larger bins you can think of some optimizations, for example, avoid the worst case scenario by sorting bins from smallest to longest, or, depending on the nature of elements, represent bins as bitmasks.
You could count all elements and take various comparison with same indices.
function x([...data]) {
while (data.some(Array.isArray)) {
const
counts = data.reduce((r, a, i) => {
if (Array.isArray(a)) a.forEach(v => (r[JSON.stringify(v)] = r[JSON.stringify(v)] || []).push(i));
return r;
}, {}),
entries = Object.entries(counts),
update = ([k, v]) => {
if (v.length === 1) {
data[v[0]] = JSON.parse(k);
return true;
}
};
if (entries.some(update)) continue;
const grouped = entries.reduce((r, [, a]) => {
const key = JSON.stringify(a);
r[key] = (r[key] || 0) + 1;
return r;
}, {});
Object.entries(grouped).forEach(([json, length]) => {
const indices = JSON.parse(json);
if (indices.length === length) {
let j = 0;
indices.forEach(i => data[i] = data[i][j++]);
return;
}
if (length === 1) {
const value = JSON.parse(entries.find(([_, a]) => JSON.stringify(a) === json)[0]);
indices.forEach(i => data[i] = data[i].filter(v => v !== value));
data[indices[0]] = value;
}
});
}
return data;
}
console.log(...x([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]));
console.log(...x([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5]]));
console.log(...x([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]));
Here is an implementation based around counting occurrences across the arrays.
It first creates a map indexed by value counting the number of inner arrays each value occurs in. It then sorts by inner array length to prioritize shorter arrays, and then iterates over each inner array, sorting by occurrence and selecting the first non-duplicate with the lowest count, or, if there are no unique values, the element with the lowest count.
const
occurrencesAcrossArrays = (arr) =>
arr
.reduce((a, _arr) => {
[...new Set(_arr)].forEach(n => {
a[n] = a[n] || 0;
a[n] += 1;
});
return a;
}, {}),
generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr)
return arr
.sort((a, b) => a.length - b.length)
.reduce((a, _arr) => {
_arr.sort((a, b) => dist[a] - dist[b]);
let m = _arr.find(n => !a.includes(n));
if (m !== undefined) {
a.push(m);
} else {
a.push(_arr[0]);
}
return a;
}, []);
};
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
Edit
In response to your comment – The situation seems to be emerging because the values all have the same occurrence count and are sequential.
This can be solved by keeping a running count of each value in the result array, and sorting each inner array by both by this running occurrence count as well as the original distribution count.This adds complexity to the sort, but allows you to simply access the first element in the array (the element with the lowest rate of occurrence in the result with the lowest occurrence count across all arrays).
const
occurrencesAcrossArrays = (arr) =>
arr
.reduce((a, _arr) => {
[...new Set(_arr)].forEach(n => {
a[n] = a[n] || 0;
a[n] += 1;
});
return a;
}, {}),
generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr)
return arr
.sort((a, b) => a.length - b.length)
.reduce((acc, _arr) => {
_arr.sort((a, b) => (acc.occurrences[a] || 0) - (acc.occurrences[b] || 0) || dist[a] - dist[b]);
let m = _arr[0]
acc.occurrences[m] = acc.occurrences[m] || 0;
acc.occurrences[m] += 1;
acc.result.push(m);
return acc;
}, { result: [], occurrences: {} })
.result; // return the .result property of the accumulator
};
console.log(generateCombination([[2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6]]).toString());
// 2,3,4,5,6,2,3
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
// 1,2,3,4,5
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
// 1,2,4,5,3
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
//1,2,4,5,3,9,6,10,7,8
console.log(generateCombination([[1], [2, 3,], [3, 4, 5], [3, 4, 5, 6], [2, 3, 4, 5, 6, 7]]).toString());
// 1,2,4,6,7
A note on .reduce()
If you're having trouble getting your head around .reduce() you can rewrite all the instances of it in this example using .forEach() and declaring accumulator variables outside of the loop. (This will not always be the case, depending on how you manipulate the accumulator value within a reduce() call).
Example below:
const occurrencesAcrossArrays = (arr) => {
const occurrences = {};
arr.forEach(_arr => {
[...new Set(_arr)].forEach(n => {
occurrences[n] = occurrences[n] || 0;
occurrences[n] += 1;
});
});
return occurrences;
};
const generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr);
const result = [];
const occurrences = {};
arr.sort((a, b) => a.length - b.length);
arr.forEach(_arr => {
_arr.sort((a, b) => (occurrences[a] || 0) - (occurrences[b] || 0) || dist[a] - dist[b]);
let m = _arr[0]
occurrences[m] = occurrences[m] || 0;
occurrences[m] += 1;
result.push(m);
});
return result;
};
console.log(generateCombination([[2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6]]).toString());
// 2,3,4,5,6,2,3
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
// 1,2,3,4,5
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
// 1,2,4,5,3
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
//1,2,4,5,3,9,6,10,7,8
console.log(generateCombination([[1], [2, 3,], [3, 4, 5], [3, 4, 5, 6], [2, 3, 4, 5, 6, 7]]).toString());
// 1,2,4,6,7
You could solve this problem using a MILP-model. Here is one implementation in MiniZinc (data has been extended to seven days):
int: Days = 7;
int: Items = 5;
set of int: DAY = 1..Days;
set of int: ITEM = 1..Items;
array[DAY, ITEM] of 0..1: A = % whether item k is allowed on day i
[| 1, 1, 0, 1, 0
| 1, 1, 0, 0, 0
| 1, 1, 0, 0, 0
| 0, 1, 0, 1, 1
| 1, 1, 0, 0, 0
| 0, 1, 0, 1, 1
| 1, 1, 1, 0, 1 |];
array[DAY, ITEM] of var 0..1: x; % 1 if item selected k on day i, otherwise 0
array[DAY, DAY, ITEM] of var 0..1: w; % 1 if item k selected on both day i and day j, otherwise 0
% exactly one item per day
constraint forall(i in DAY)
(sum(k in ITEM)(x[i, k]) = 1);
% linking variables x and w
constraint forall(i, j in DAY, k in ITEM where i < j)
(w[i, j, k] <= x[i, k] /\ w[i, j, k] <= x[j, k] /\ w[i, j, k] >= x[i, k] + x[j, k] - 1);
% try to minimize duplicates and if there are duplicates put them as far apart as possible
var int: obj = sum(i, j in DAY, k in ITEM where i < j)(((Days - (j - i))^2)*w[i, j, k]);
solve minimize obj;
output
["obj="] ++ [show(obj)] ++
["\nitem="] ++ [show([sum(k in ITEM)(k*x[i, k]) | i in DAY])];
Running gives:
obj=8
item=[2, 1, 5, 4, 3, 2, 1]
The following package looks promising for a JavaScript implementation: https://www.npmjs.com/package/javascript-lp-solver

Remove a specific amount of elements in the array

i want to specify how many 1 elements I want to remove within that array:
const array = [1, 1, 2, 3, 1, 5];
I tried like that:
const array = [1, 1, 2, 3, 1, 5];
const i = array.indexOf(1);
if (i > - 1) {
array.splice(i, 1);
}
but this remove just first element 1 in array
Try this, Array.prototype.filter will create a new array and will not mutate or change the array on which it is called.
const arr = [1, 1, 2, 3, 1, 5];
const newArr = arr.filter((item) => item !== 1);
console.log(newArr);
const removeArrayItem = (array, item) => array.filter((i) => i !== item);
console.log(removeArrayItem([1, 2, 2, 2, 2, 3, 4, 5], 2));
console.log(removeArrayItem([1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 8, 8], 8));
// or using reduce
const removeDuplicateItem = (arr, itemToRemove, count) =>
arr.reduce(
(accumulator, currentItem) => {
if (
accumulator.count &&
accumulator.count > 0 &&
currentItem === itemToRemove
) {
accumulator.count -= 1;
return accumulator;
}
accumulator.result.push(currentItem);
return accumulator;
},
{
count,
result: [],
},
).result;
// This will remove 5 number twos
console.log(removeDuplicateItem([1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 8, 8], 2, 5));
You need to iterate the count and check if an item is available for removing.
function remove(array, value, count) {
while (count--) {
const i = array.indexOf(value);
if (i === -1) break;
array.splice(i, 1);
}
}
const array = [1, 1, 2, 3, 1, 5];
remove(array, 1, 2);
console.log(array);
If you want to remove only the amount of 1s you specify,
You can use a for loop with 2 conditions,
one for array size and the second for the number of times 1 was found and removed.
const array = [1, 1, 2, 3, 1, 5];
const counter = 2;
for(let i = 0 , n = 0; i < array.length && n < counter; i++) {
if(array[i] === 1) {
array.splice(i, 1);
i -= 1;
n++;
}
}
console.log(array);
You can use a while loop to remove N number of elements with this value:
const removeNInstancesOfX = (array, n, x) => {
let i = null, count = 0, arr = [...array];
while ((i = arr.indexOf(1)) !== -1 && count++ < n)
arr.splice(i, 1);
return arr;
}
let array = [1, 1, 2, 3, 1, 5];
array = removeNInstancesOfX(array, 2, 1);
console.log(...array);

Split array into different size chunks (4, 3, 3, 3, 4, 3, 3, 3, etc)

I have an array like so: [1, 2, 3, 4, 5, 6, 7, 9, 10]. I need to chunk it into different size chunks, yet with a simple pattern of: 4, 3, 3, 3, 4, 3, 3, 3 like so:
[
[ // four
1,
2,
3,
4
],
[ // three (1/3)
5,
6,
7
],
[ // three (2/3)
8,
9,
10
],
[ // three (3/3)
11,
12,
13
],
[ // four
14,
15,
16,
17
],
[ // three (1/3)
18,
19,
20
], // and so on..
]
I have tried with this code I have customized:
const arr; // my array of values
const chuncked = arr.reduce((acc, product, i) => {
if (i % 3) {
return acc;
} else if (!didFourWayReduce) {
didFourWayReduce = true;
fourWayReduces++;
if ((fourWayReduces - 1) % 2) { // only make every second a "4 row"
return [...acc, arr.slice(i, i + 3)];
} else {
return [...acc, arr.slice(i, i + 4)];
}
} else {
didFourWayReduce = false;
return [...acc, arr.slice(i, i + 3)];
}
}, []);
And it works, almost, expect that the first chunk of threes (1/3) have the last element of the chunk with 4. So 1 key is repeated every first chunk of three. Like so:
[
[
1,
2,
3,
4
],
[
4, // this one is repeated, and it shouldn't be
5,
6
]
]
You could take two indices, one for the data array and one for sizes. Then slice the array with a given length and push the chunk to the chunks array.
Proceed until end of data.
var data = Array.from({ length: 26 }, (_, i) => i + 1),
sizes = [4, 3, 3, 3],
i = 0,
j = 0,
chunks = [];
while (i < data.length) chunks.push(data.slice(i, i += sizes[j++ % sizes.length]));
console.log(chunks);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const arr = Array.from({ length: 100 }, (_, i) => i);
const copy = [...arr];
const sizes = [4, 3, 3, 3];
const result = [];
let i = 0;
while (i <= arr.length && copy.length) {
result.push(copy.splice(0, sizes[i % sizes.length]));
i++;
}
console.log(result);
A recursive approach is fairly elegant:
const chunks = (xs, [s, ...ss]) =>
xs.length ? [xs .slice (0, s), ... chunks (xs .slice (s), [...ss, s])] : []
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
const sizes = [4, 3, 3, 3]
console .log (chunks (data, sizes))
.as-console-wrapper { max-height: 100% !important; top: 0; }
By replacing [s, ...ss] with [...ss, s], we pass a cycled version of the sizes array, so that for instance, [4, 3, 3, 3] becomes [3, 3, 3, 4]. This makes it easy to parse step-by-step.
Mod operator to check if it should be 4 or 3. Use two arrays just to make it easier (can be done with one)
const groupIt = arr => arr.reduce(({
group,
out
}, v, i) => {
var max = out.length % 4 === 0 ? 4 : 3
group.push(v)
if (group.length === max || i === arr.length - 1) {
out.push(group)
group = []
}
return {
group,
out
}
}, {
group: [],
out: []
}).out
console.log(groupIt([1, 2, 3, 4, 5, 6, 7, 8]))
var test = (new Array(30)).fill(0).map((x,i) => i + 1)
console.log(groupIt(test))
with just one:
const groupIt = arr => arr.reduce((out, v, i) => {
var max = (out.length - 1) % 4 === 0 ? 4 : 3
out[out.length - 1].push(v)
if (out[out.length - 1].length === max) {
out.push([])
}
return out
}, [[]])
console.log(groupIt([1, 2, 3, 4, 5, 6, 7, 8]))
var test = (new Array(30)).fill(0).map((x, i) => i + 1)
console.log(groupIt(test))
This answer is similar to that of Nina Scholz, but uses a for loop, which I personally find more clear.
const arr = Array.from({length: 100}, (_, i) => i + 1);
const sizes = [4, 3, 3, 3];
const result = [];
for (let i = 0, j = 0; i < arr.length; i += sizes[j], j = (j + 1) % sizes.length) {
result.push(arr.slice(i, i + sizes[j]));
}
console.log(result);

JavaScript move along all items in array by X number

I'm wanting to create a function which accepts 2 arguments, first argument is an array, second argument is a number of index positions to move all the array items.
So for example if I passed exampleFunc([1,2,3,4,5], 2) it should move all items 2 places to the right, so returns [4,5,1,2,3]. I've done the following, however is there a more eloquent / efficient way of doing this? Also if I wanted to reverse the direction and condense into 1 function and not two as done below, any suggestions how to do this other than putting conditionals around the different part of each function? Tried using .splice() method but didn't really got anywhere. Any help would really be appreciated!
const moveArrayPositionRight = (array, movePositions) => {
let newArray = new Array(array.length);
for (i = 0; i < array.length; i++) {
let newIndex = i - movePositions;
if (newIndex < 0) {
newIndex += array.length;
}
newArray[i] = array[newIndex];
}
return newArray;
};
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 2)); // output: [8, 10, 2, 4, 6]
const moveArrayPositionLeft = (array, movePositions) => {
let newArray = new Array(array.length);
for (i = 0; i < array.length; i++) {
let newIndex = i - movePositions;
if (newIndex < 0) {
newIndex += array.length - 1;
}
newArray[i] = array[newIndex];
}
return newArray;
};
console.log(moveArrayPositionLeft([3, 6, 9, 12, 15], 2)); // output: [9,12,15,3,6]
You have the index of the position where you want to slice the array up and rearrange it, so you can use .slice to do exactly that - extract the sub-arrays that need to be rearranged, and put into a new array:
const moveArrayPositionRight = (array, movePositions) => [
...array.slice(array.length - movePositions),
...array.slice(0, array.length - movePositions)
];
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 2)); // output: [8, 10, 2, 4, 6]
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 3)); // expected [6, 8, 10, 2, 4]
.slice can also take negative indicies to slice an amount from the end instead of from the beginning:
const moveArrayPositionRight = (array, movePositions) => [
...array.slice(-movePositions),
...array.slice(0, -movePositions)
];
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 2)); // output: [8, 10, 2, 4, 6]
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 3)); // expected [6, 8, 10, 2, 4]
Can also use .concat instead of spread
const moveArrayPositionRight = (array, movePositions) => array
.slice(array.length - movePositions)
.concat(array.slice(0, array.length - movePositions));
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 2)); // output: [8, 10, 2, 4, 6]
console.log(moveArrayPositionRight([2, 4, 6, 8, 10], 3)); // expected [6, 8, 10, 2, 4]
Same sort of thing for moveArrayPositionLeft:
const moveArrayPositionLeft = (array, movePositions) => [
...array.slice(movePositions),
...array.slice(0, movePositions)
];
console.log(moveArrayPositionLeft([3, 6, 9, 12, 15], 2)); // output: [9,12,15,3,6]

Categories