JavasScript: chunk method [duplicate] - javascript

This question already has answers here:
Split array into chunks
(73 answers)
Closed 4 years ago.
I'm trying to implement a chunk function in javascript similar to lodash chunk. It seems like i'm hitting an indexing issue relating to the count here but I can't figure it out.
// chunk array function breaks an array into chunks of defined size
// [1, 2, 3, 4, 5, 6, 7, 8]
// with size 2
// should output: [[1,2], [3,4], [5,6], [7,8]]
const testArr = [1, 2, 3, 4, 5, 6, 7, 8]
const testArr2 = [1, 2, 3, 4, 5, 6, 7]
function chunk(arr, size){
let newArr = []
let tempArr = []
let iterations;
let remainder;
if(Number.isInteger(arr.length / size)){
iterations = arr.length / size
} else {
iterations = size.toString().split('.')[0]
// how many remain?
remainder = arr.length % size
}
// theres an issue somewhere in here relating to count
let count = 0
while(count < iterations){
tempArr = []
for(let i = count; i < (size + count); i++){
tempArr.push(arr[i])
}
newArr.push(tempArr)
count++
}
// if(remainder){
// for(let i = count; i < count + remainder; i++){
// tempArr.push(arr[i])
// }
// }
return newArr
}
console.log(chunk(testArr, 2))
I'm interested in 2 different things:
Whats wrong with my code example?
How would YOU implement this better? Clearly my example is not very
clean and I'm curious how others would handle it (some .map
.reduce stuff maybe?) i tried reading lodash docs but they use a lot of internal functions that make it a little confusing.
actual output is: [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ] ]
output should be: [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
Thanks!

A simpler way to do this would be:
let size = 2;
[1, 2, 3, 4, 5, 6, 7, 8].reduce((carry, current, index) => {
// get the current array bucket. if it doesn't exist, create it.
let el = carry[Math.floor(index / size)] = carry[Math.floor(index / size)] || [];
// push the current element onto the current bucket
el.push(current);
// return our new array
return carry;
}, [])
The issue with your code is just that you need to do:
tempArr.push(arr[i + count])

Related

Javascript get array element from the condition of summation of array element

I have an Array, arr = [2,4,8,7,3,6] I want to make each element of it be summation when the result is 10 , then save the element it would be arranged to another array.
make the element that result is 10 close each other like 2 and 8, add to another element named arr2.
result i need : arr2[2,8,3,7,4,6]
my code :
const arr = [2, 4, 8, 7, 3, 6];
let arr2 = [];
for (let i = 0; i < arr.length(); i++) {
let Number1 = arr[i];
let Number2 = arr[(i + 1)];
if (Number1 + Number2 === 10) {
let element1 = arr.indexOf(Number1);
let element2 = arr.indexOf(Number2);
arr2.push(element1, element2);
}
console.log(arr2[i]);
}
someone can solve my problem please ?
If you need to create arr2 so that the items sum up to 10 you can make use of a simple map here:
const arr = [2, 4, 8, 7, 3, 6];
const arr2 = arr.map((item) => 10 - item)
console.log(arr2);
You should first loop through the array to create a dictionary of value to index, then loop the array again and lookup for the complement of the current value to the target. If it exist then yes you got the answer.
.filter(x => x > i) is to search for complement that has higher index than current one so that we will not get duplicated result pushed. For example input is [2, 8], you don't want to get [2, 8, 8, 2]
Here is my solution
const arr = [2, 4, 8, 7, 3, 6];
let arr2 = [];
function solution(target: number, input: number[]): number[] {
const result: number[] = [];
const lookUpMap: {[key: number]: number[]} = {};
let i = 0;
for (const each of input) {
if (!(each in lookUpMap)) {
lookUpMap[each] = [];
}
lookUpMap[each].push(i);
i++;
}
i = 0;
for (const each of input) {
const difference = target - each;
if (difference in lookUpMap) {
const complementIndex = lookUpMap[difference].filter(x => x > i)[0];
if (complementIndex) {
result.push(input[i], input[complimentingIndex]);
}
}
i++;
}
return result;
}
arr2 = solution(10, arr);
console.log(arr2);
Assuming a valid result can be created for the given arr. A fairly simple solution would be to sort the array first. Then step through half the array and take the element on the current index, and the element on the inverse index (length - 1 - index). And push() those both in the resulting array.
So here in steps, given you have the following array:
[2, 4, 8, 7, 3, 6]
You sort it:
[2, 3, 4, 6, 7, 8]
Then you step through half the indexes and take each element, and the element on the inverse index.
[2, 3, 4, 6, 7, 8]
// \ \ \/ / /
// \ ------ / -> [2, 8, 3, 7, 4, 6]
// ----------
const arr = [2, 4, 8, 7, 3, 6];
const sortedArr = Array.from(arr).sort((a, b) => a - b); // ascending
const length = sortedArr.length;
const nPairs = length / 2;
const arr2 = [];
for (let i = 0; i < nPairs; ++i) {
arr2.push(
sortedArr[i],
sortedArr[length - 1 - i],
);
}
// or if you want a more functional approach:
// const arr2 = Array.from({ length: nPairs }).flatMap((_, i) => [sortedArr[i], sortedArr[length - 1 - i]]);
console.log(arr2);
Do note that this is probably not the fastest solution, because sorting is non-linear.
Obviously this solution does not work if an invalid input is given, like [7,2,1,8] which can never produce a valid output.

Javascript: Arrays built during for loop have their order reset [duplicate]

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 4 years ago.
This code seems straightforward enough
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
store.push(arr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
I'm expecting it to return
[[1,2,3,4,5,6],[2,3,4,5,6,1],[3,4,5,6,1,2],[4,5,6,1,2,3],[5,6,1,2,3,4],[6,1,2,3,4,5]]
But when the loop is complete, it shows
[[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]]
When printing the values in the console, they appear correct, but when the store variable is logged, they are all reordered.
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6, 1]
[3, 4, 5, 6, 1, 2]
[4, 5, 6, 1, 2, 3]
[5, 6, 1, 2, 3, 4]
[6, 1, 2, 3, 4, 5]
Why is this occurring?
There is a similar question here, but it doesn't really provide an answer for my case.
Creating a pair of arrays from an array resulting in circular array
Just make sure you are inserting not the same reference to your array:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
store.push(Array.from(arr)) // <-- Make sure not the same ref
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
store contains the same instance of arr 6 times. You modify it and print it every time, then add the same object to store, then modify it again.
To get your desired behaviour you need to add a new instance every time e.g. by cloning it when you add it.
You could push a copy which does not keep the same object reference.
let arr = [1, 2, 3, 4, 5, 6]
let store = [];
for (i = 0; i < arr.length; i++) {
store.push(arr.slice()) // just take a copy
arr.push(arr.shift())
}
console.log(store.map(a => a.join(' ')))
Alternate approach leaving original array untouched and using splice() to remove beginning elements and concat() to add to the end
let arr = [1,2,3,4,5,6];
let store = arr.map((_,i)=> {
let a = arr.slice();
return i ? a.concat(a.splice(0,i)) : a;
})
console.log(JSON.stringify(store))
On every loop, you are pushing the reference of the array to store
Example:
Loop - reference of arr - 0x112, then store[ i ] = reference to 0x112
At end:
arr - refer to 0x112 - value = [1, 2, 3, 4, 5, 6]
store[ ] = [ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112)]
Use this:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
let newArr = arr.slice();
store.push(newArr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))

Splitting array into groups of 3 in javascript [duplicate]

This question already has answers here:
How to split a long array into smaller arrays, with JavaScript
(26 answers)
Split array into chunks
(73 answers)
Closed 4 years ago.
I am trying to split an array of objects into sets of 3 and there is a slight problem. I run the code and it splits the first group into 2 and the rest into 3. I want the last group to have the remaining elements. So for instance if there are 21 objects then the last group should have 2 but instead the first group is the one with 2. How can I make the last group be the one with the remaining objects?
var newData = [];
var setOfThree = [];
for (i = 0; i < data.length; i++) {
setOfThree.push(data[i]);
if (i % 3 == 1) {
newData.push(setOfThree);
setOfThree = [];
}
}
So the data ends up looking like this:
Here's a very clean and efficient solution (leverages the fact that Array.prototype.slice automatically truncates results):
let groupByN = (n, data) => {
let result = [];
for (let i = 0; i < data.length; i += n) result.push(data.slice(i, i + n));
return result;
};
console.log(JSON.stringify(groupByN(3, [ 1 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7, 8 ])));
The first array gets 2 items because, when i === 1 1%3 will result to 1
Starting from counter 1 could be one solution
data = [1,2,3,4,5,6,7]
var newData = [];
// var setOfThree = []; // not required
var j = 0
newData.push([]);
//pushing at the very begining, this way we won't miss if the data
// is not in groups of 3
for (i = 1; i <= data.length; i++) {
// always updating the final array
newData[j].push(data[i-1]);
if (i % 3 == 0) {
newData.push([]);
j++;
}
}
if (newData[0].length === 0) {
// if the data you received was epmty
newData.pop()
}
console.log(newData)
Here a recursive implementation, with some es6 sugar
var input = [1,2,3,4,5,6,7,8]
function groupByThree([a,b,c,...rest]){
if (rest.length === 0) return [[a,b,c].filter(x => x!==undefined)]
return [[a,b,c]].concat(groupByThree(rest))
}
console.log(groupByThree(input))

Sorting array by variable number of columns

Say I have an array
var originalArray = [1,2,3,4,5,6,7]
I want to display to apply
function orderToColumn (originalArray, numberofcolumn) to get a return value like so
Array [ 1, 4, 7, 2, 5, undefined, 3, 6, undefined ]
the point being I want to be able to display my array in the following format:
1 4 7
2 5
3 6
Heres my attempt so far: https://jsfiddle.net/042o7rv9/
The array could be of any size and the numberofcolumn>=1.
You can do something like this.
var a = [1,2,3,4,5,6,7];
function orderToColumn(arr,col){
var len = col*Math.ceil(arr.length / col);
console.log(len);
var newArr=[];
for(var i = 0;i<col;i++){
for(var j=0;j<len/col;j++){
newArr.push(arr[j*col+i]);
}
}
return newArr;
}
var b = orderToColumn(a,3);
console.log(b); // [1, 4, 7, 2, 5, undefined, 3, 6, undefined]
You might do functionally as follows;
function columnize(a,n){
var count = Math.ceil(a.length/n);
return a.reduce((p,c,i) => i%count === 0 ? p.concat([[c]]) : (p[p.length-1].push(c),p),[]);
}
var originalArray = [1,2,3,4,5,6,7],
result = columnize(originalArray,3);
console.log(result);

Functional way for custom iteration [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
How can I use only map, reduce or filter or any functional way to create a custom iteration on an array?
Let's say I wanna map an array to another array which holds the sum of each three adjacent elements in the source array:
var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]
Or make a bucket of two elements:
var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]
For the second one I have the following but that doesn't look very functional as I'm accessing array by index:
function* pairMap(data) {
yield* data.map((item, index) => {
if (index > 0) {
return [data[index - 1], item];
}
});
}
I'm interested in the functional way of doing this.
Let's say I wanna map an array to another array which holds the sum of each three adjacent elements in the source array:
var source = [1, 2, 3, 4, 6, 7, 8] // to [6, 17, 8]
Maps create 1:1 relationships, so this wouldn't be appropriate use of map. Instead, a reduce or ("fold") would be better here.
const comp = f=> g=> x=> f (g (x));
const len = xs=> xs.length;
const isEmpty = xs=> len(xs) === 0;
const concat = xs=> ys=> ys.concat(xs);
const chunk= n=> xs=>
isEmpty (xs)
? []
: concat (chunk (n) (xs.slice(n))) ([xs.slice(0,n)]);
const reduce = f=> y=> xs=> xs.reduce((y,x)=> f(y)(x), y);
const map = f=> xs=> xs.map(x=> f(x));
const add = x=> y=> y + x;
const sum = reduce (add) (0);
var source = [1, 2, 3, 4, 6, 7, 8];
comp (map (sum)) (chunk (3)) (source);
//=> [ 6, 17, 8 ]
So as you can see, we first transform the source into chunks of 3, then we map the sum function over each chunk.
When you hear people talking about "declarative" code, the last line is quite clear and worries little about implementation. We're not telling the computer how to do its job. There's no for/while loops, no extraneous vars or iterators, no logic, etc.
"idgaf how, just break source up into groups of 3, and then sum each part"
// very declaration, wow
comp (map (sum)) (chunk (3)) (source);
Or make a bucket of two elements:
var source = [1, 2, 3, 4, 5, 6, 7] // to [[1, 2], [3, 4], [5, 6], [7]]
Using the same code above
var source = [1, 2, 3, 4, 5, 6, 7];
chunk (2) (source);
// => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ] ]
For the second one I have the following but that doesn't look very functional as I'm accessing array by index:
function* pairMap(data) {
yield* data.map((item, index) => {
if (index > 0) {
return [data[index - 1], item];
}
});
}
Using the code above, you can implement pairMap easily
const pairMap = f=> comp (map (f)) (chunk (2));
var source = [1, 2, 3, 4, 5, 6, 7];
pairMap (pair => console.log(pair)) (source);
// [ 1, 2 ]
// [ 3, 4 ]
// [ 5, 6 ]
// [ 7 ]
Learn all the things
The question is "functional way for custom iteration". You'll notice my code sorta cheats by using Array.prototype.reduce and Array.prototype.map. Learning how to build these on your own was a good learning tool for me to understand that building functional loops/iterators/control is fun and simple
const isEmpty = xs=> xs.length === 0
const head = xs=> xs[0];
const tail = xs=> xs.slice(1);
const reduce = f=> y=> xs=>
isEmpty (xs)
? y
: reduce (f) (f (y) (head (xs))) (tail (xs));
const add = x=> y=> y + x;
reduce (add) (0) ([1,2,3]);
//=> 6
It works!.
OK, let's see how we'd do map
const concat = xs=> ys=> ys.concat(xs);
const append = x=> concat ([x]);
const map = f=>
reduce (ys=> x=> append (f (x)) (ys)) ([]);
const sq = x => x * x;
map (sq) ([1,2,3])
//=> [ 1, 4, 9 ]
Quiz 1: Can you write filter, some, and every using reduce ?
Troll warning: There's many different ways to implement these functions. If you start writing recursive functions, the first thing you'll want to learn about is what a tail call is. ES6 is getting tail call optimization but it won't be widespread for a while. For a while, Babel could transpile it using a while loop, but it's temporarily disabled in version 6 and will be coming back once they fix it.
Quiz 2: How can you rewrite my reduce with a proper tail call?
For first part of question you can use reduce and slice to group every 3 elements from array and then you can use map and reduce to get sum of each group.
var source = [1, 2, 3, 4, 6, 7, 8];
var result = source.reduce((r, elem, i) => {
if(i % 3 == 0) r.push(source.slice(i, i+3));
return r;
}, []);
result = result.map(e => {return e.reduce((a, el) => { return a + el })});
console.log(result)
And for second part of question, again you can use reduce with slice to group every 2 elements.
var source = [1, 2, 3, 4, 5, 6, 7]
source = source.reduce((r, e, i) => {
if(i % 2 == 0) r.push(source.slice(i, i+2));
return r;
}, [])
console.log(source)
First task with one reduce
var source = [1, 2, 3, 4, 5, 6, 7];
var r1 = source.reduce((p, c, i, a) => {
if (i % 2) p[p.length - 1].push(c);
else p.push([a[i]]);
return p;
}, []);
console.log(JSON.stringify(r1, 0, 2));
Second task with reduce and map
var source = [1, 2, 3, 4, 5, 6, 7];
var r2 = source.reduce((p, c, i, a) => {
if (p[p.length - 1].length < 3) p[p.length - 1].push(c);
else p.push([a[i]]);
return p;
}, [[]]).map(e => e.reduce((a, b) => a + b));
console.log(JSON.stringify(r2, 0, 2));

Categories

Resources