I have an array
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
I want to group it into a set of n arrays such that first n elements in result[0] next n elements in result[1] and if any element is remaining it is discarded.
let sampleOutput = [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13]] for n = 7;
Here is my code:
function group5(arr, len) {
let result = [];
let loop=parseInt(arr.length/len)
for (let i=0; i<arr.length; i+=len) {
let x = []; let limitReached = false;
for (let j=0; j<len; j++) {
if (arr[i+j]) {
x.push(arr[i+j]);
} else {
limitReached = true;
break;
}
}
if (!limitReached) {
result.push(x);
} else {
break;
}
}
return result;
}
But I am unable to get expected result. I have tried following things.
Map function
Running i loop to arr.len
Checking arr.len % 7
Creating an array for every third element.
This question is not duplicate of Split array into chunks because I have to discard extra elements that can not be grouped into sets of n.
I have to keep the original array Immutable because I am using this on props in a child component. I need a function that does not modify the original array.
It's pretty straigthforward using Array.from
const list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
function chunkMaxLength(arr, chunkSize, maxLength) {
return Array.from({length: maxLength}, () => arr.splice(0,chunkSize));
}
console.log(chunkMaxLength(list, 7, 2));
What about :
function group5(arr, len) {
let chunks = [];
let copy = arr.splice(); // Use a copy to not modifiy the original array
while(copy.length > len) {
chunks.push(copy.splice(0, len));
}
return chunks;
}
You could use a combination of reduce and filter to achieve the expected result. This example gives you a third control over length which makes the code a bit more reuseable.
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const groupNumber = 7;
const groupCount = 2;
const groupArray = (group, size, length) => group.reduce((accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator, []
).filter((single, index) => index < length)
const test = groupArray(arr, groupNumber, groupCount);
console.log(test);
Step by Step
const groupArray = (group, size, length) => {
// if (index modulus size) equals 0 then concat a group of
// length 'size' as a new entry to the accumulator array and
// return it, else return the accumulator
const reducerFunc = (accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator
// if the current index is greater than the supplied length filter it out
const filterFunc = (single, index) => index < length;
// reduce and filter original group
const result = group.reduce(reducerFunc, []).filter(filterFunc)
return result;
}
Also (apart from the existing approaches) you can have a recursive approach like this
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
console.log('Chunk with 3: ', chunks(arr, 3));
console.log('Chunk with 4: ', chunks(arr, 4));
console.log('Chunk with 5: ', chunks(arr, 5));
console.log('Chunk with 6: ', chunks(arr, 6));
console.log('Chunk with 7: ', chunks(arr, 7));
I able to solve the problem with this code
function groupN(n, arr) {
const res = [];
let limit = 0;
while (limit+n <= arr.length) {
res.push(arr.slice(limit, n + limit));
limit += n
}
return res
}
I usually prefer declarative solutions (map, reduce, etc), but in this case I think a for is more understandable:
function groupArray(array, num) {
const group = [];
for (let i = 0; i < array.length; i += num) {
group.push(array.slice(i, i + num));
}
return group;
}
Related
I have an array a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7]
I want to fetch all the duplicate pair in this array list.
Since there are pairs of 2 and 7 the output should be -
Output: [2, 7]
I tried writing my own logic but I am very weak in that area. Can somebody help?
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
for (let i = 0; i < sorted_arr.length; i++) {
let matchingElementCount = 1;
for (let j = i + 1; j < sorted_arr.length - i; j++) {
if (sorted_arr[j] === sorted_arr[i]) {
++matchingElementCount;
} else {
if(matchingElementCount % 2 === 0) {
results.push(sorted_arr[i]);
}
i = j - 1;
break;
}
}
}
return results; } var a = [1,1,1,2,2,3,3,3,4,6,6,6,7,7]; var duplicateValues= getDuplicateArrayElements(a);
You can achieve your result by using reduce and forEach.
const arr = [1,1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
// Generate a hashmap from the given array for counting the frequency.
const hashMap = arr.reduce((a, c) => {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
const pair = [];
// If the frequency is divided by 2 then push the key of the hashMap into pair array.
Object.entries(hashMap).forEach(([k, v]) => {
if (v % 2 === 0) {
[...Array(Math.floor(v / 2))].forEach(_ => pair.push(k));
}
})
console.log(pair);
You can grab the frequency of each number, and then filter out any which have an odd frequency. You can then .flatMap() the frequencies to an array containing your number for each pair you found like so:
const a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
const freq = a.reduce((m, n) => m.set(n, (m.get(n) || 0) + 1), new Map);
const res = [...freq].filter(([n, count]) => count % 2 == 0).flatMap(([n, c]) => Array(c/2).fill(n));
console.log(res);
This way, if you have four 1s (ie: two pairs of 1s), the filter will pick up on that, allowing you to flat-map the [1, 4] array to an array of [1, 1], which is merged into the larger resulting array.
You could create a helper map and keep the counts of each number as the values and the numbers itself as the keys. After iterating through the array, you only need to find the ones with a count divisible by 2:
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7]
function findDuplicates(arr) {
const map = {};
for (const curr of arr) {
if (!map[curr]) {
map[curr] = 0;
}
map[curr]++;
}
const res = [];
for (const key in map) {
if (map.hasOwnProperty(key) && map[key] % 2 === 0) {
res.push(Number.parseInt(key));
}
}
return res;
}
console.log(findDuplicates(a));
You can first count the occurrence of each numbers and if it is greater than 0 and divisible by 2 then add these to final result else don't
function getDuplicateArrayElements(arr) {
let map = {}
let results = [];
for (let num of arr) {
map[num] = map[num] || 0
map[num]++
}
return Object.keys(map)
.filter(v => map[v] && map[v] % 2 === 0)
.map(v => new Array(map[v]/2).fill(+v))
.flat()
.sort()
}
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7,8,8,8,8];
var duplicateValues = getDuplicateArrayElements(a);
console.log(duplicateValues)
const a = {};
[1,1,1,2,2,3,3,3,4,6,6,6,7,7].forEach(v => {a[v] = a[v] ? a[v] + 1 : 1});
const l = [];
Object.keys(a).forEach(k => !(a[k] % 2) && l.push(k));
Here you go:
function getDuplicateArrayElements(arr){
var dupilcates=arr.filter(x => arr.filter(y=>y==x).length==2);
var found=[];
for(var i=0;i<dupilcates.length;i=i+2)
found.push(dupilcates[i]);
return found;
}
This will give you the desired pairs. with [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7] input it will return [1,1,2,6,6,7]:
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
let i = 0;
while (i < sorted_arr.length) {
let counter = 1;
let j = i;
while (sorted_arr[j] === sorted_arr[j+1]) {
counter++;
j++;
}
if (counter%2 == 0) {
results.push(...Array(counter/2).fill(sorted_arr[i]))
}
i += counter;
}
return results;
}
var a = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7];
console.log(getDuplicateArrayElements(a));
Another rather concise solution:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
uniques = new Set(a); //filter out duplicates
res = [];
uniques.forEach((key)=>{
if(a.filter(elem => elem === key).length === 2){res.push(key)};
//filter out only the elements which match the key being tested
//if there are 2, push to result
})
Edit: even more concise, but perhaps less efficient:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
res = Array.from(new Set(a.filter(elem => a.filter(el => el === elem).length === 2)));
Javascript has awesome JSON object, in my opinion, you can use json as a dictionary;
{ key: _value }.
Loop throw array one times, no sort, no slice
key is array's element value, _value is frequency
var frequencies = {};
for (let i = 0; i < a.length; a++) {
if (result[a[i]] == 'over') continue;
if (result[a[i]] == undefined) { // First times
result[a[i]] = 1
} else if (result[a[i]] == 1) { // Second times
result[a[i]] = 2
} else { // Ignore if > 2
result[a[i]] = 'over'
}
}
// result: {1: "over", 2: 2, 3: "over", 4: "over", 6: "over", 7: 2}
so now pick keys have value equal 2
function getDuplicateArrayElements(numbers: number[]): number[] {
const occurences = new Map<number, number>();
for (let number of numbers) {
if (occurences.has(number)) {
const current = occurences.get(number)!;
occurences.set(number, current + 1);
} else
occurences.set(number, 1)
}
return (
Array
.from(occurences.entries())
.reduce<number[]>(
(accumulator, [key, value]) => {
if (value === 2) {
return accumulator.concat(key)
}
return accumulator
},
[]
)
)
}
const a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6, 6, 6, 7, 7];
getDuplicateArrayElements(a); // [2, 7]
I've a JavaScript array and sum as input
array = [4,8,2,4,2,2,8,12,4,2, 2]
sum = 12 // all the time sum will be 12
I want 2d array, the numbers in batches should be sum equals or less than 12
The output array should look like
[
[4,8],
[2,4,2,2,2],
[8, 4],
[12],
[2]
]
4 + 8 = 12
2 + 4 + 2 + 2 + 2 = 12
...
2 is left at the end
Other examples
1) array = [6,5,3,3,3,2,2,2,2]
sum = 12
output: [ [6,3,3], [5,3,2,2], [2,2] ]
One the number is allotted to subset, it should not used to other subset
remaining numbers can be added to the last but sum should be less than 12, else add one more array and add remaining ones
The input array can have any integer from 1 - 12
How can I get the output I want?
Try this function. I commented the code as much as possible to clarify it.
const example1 = [4, 8, 2, 4, 2, 2, 8, 12, 4, 2, 2];
const example2 = [6, 5, 3, 3, 3, 2, 2, 2, 2];
const example3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const example4 = [5,12,3,4,4,1,1,1,5,8,12,6,9,11,6];
const example5 = [4, 2, 1, 2, 3, 3, 5, 7, 8, 9];
const lookAhead = function(array, searchFor) {
return array.some(val => {
return val <= searchFor;
});
}
function findPairs(inputArray) {
// First sort array in descending order
inputArray.sort((a, b) => b - a);
console.log("input", JSON.stringify(inputArray.slice(0)));
// set variables
const pairArray = [];
const max = 12;
inputArray.forEach(function(num, index) {
// when looping the array we will replace values with null once completed,
// Therefore if value is null no need to go futher
if (num == null)
return;
// initiate pair value with current number
const pair = [num];
// set it to null in input array
inputArray[index] = null;
// if number equals to max (ie. 12) no need to go futher
if (num == max) {
pairArray.push(pair);
return;
}
let total = num;
// Loop through array again to see matching numbers
for (let i = 0; i < inputArray.length; i++) {
// Don't go futher if it is a null value
if (inputArray[i] == null)
continue;
const add = total + inputArray[i];
/* if the total is less than max (12) then we check if we have an edge case
* For example in an array like [6, 5, 3, 3, 3], 6 + 5 is 11 but in next loops we
* will not find any "1" to get to 12. Therefore we escape this iteration and check
* next numbers. In this case the result would be 6 + 3 + 3
*/
if (add < max) {
const found = lookAhead(inputArray.slice(i), max - add);
if (found) {
pair.push(inputArray[i]);
total = add;
inputArray[i] = null;
}
} else if (add == max) {
// The addition is equals to max. Push the number and set it to null in input array
pair.push(inputArray[i]);
inputArray[i] = null;
total = 0;
break;
}
}
// Push pair array from this iteration to pairArray
pairArray.push(pair);
});
console.log("output", JSON.stringify(pairArray));
console.log("-------");
}
findPairs(example1);
findPairs(example2);
findPairs(example3);
findPairs(example4);
findPairs(example5);
A little complex to understand but here you go...
let originalArray = [7, 7, 7, 7, 7]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([]);
originalArray.forEach(element => {
for (let i = 0; i < twoDiArray.length; i++) {
if (CalculateSum(twoDiArray[i], element) <= 12) {
twoDiArray[i].push(element);
break;
} else {
if (twoDiArray.length - 1 === i) {
twoDiArray.push([element]);
break;
}
}
}
})
console.log(twoDiArray)
Here you... I will keep both answers open for future use of others...
let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([originalArray[0]]);
originalArray.splice(0, 1);
do {
originalArray.forEach((element, index) => {
for (let i = 0; i < twoDiArray.length; i++) {
let summ = CalculateSum(twoDiArray[i], element);
if (summ === 12) {
twoDiArray[i].push(element);
originalArray.splice(index, 1);
break;
} else {
if (index === originalArray.length - 1) {
if (CalculateSum(twoDiArray[twoDiArray.length - 1], originalArray[0]) <= 12) {
twoDiArray[twoDiArray.length - 1].push(originalArray[0]);
break;
} else {
twoDiArray.push([originalArray[0]]);
}
originalArray.splice(0, 1);
}
}
}
})
}
while (originalArray.length > 0);
console.log(twoDiArray)
Imagine I have an array:
A = Array(1, 2, 3, 4, 5, 6, 7, 8, 9);
And I want it to convert into 2-dimensional array (matrix of N x M), for instance like this:
A = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9));
Note, that rows and columns of the matrix is changeable.
Something like this?
function listToMatrix(list, elementsPerSubArray) {
var matrix = [], i, k;
for (i = 0, k = -1; i < list.length; i++) {
if (i % elementsPerSubArray === 0) {
k++;
matrix[k] = [];
}
matrix[k].push(list[i]);
}
return matrix;
}
Usage:
var matrix = listToMatrix([1, 2, 3, 4, 4, 5, 6, 7, 8, 9], 3);
// result: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can use the Array.prototype.reduce function to do this in one line.
ECMAScript 6 style:
myArr.reduce((rows, key, index) => (index % 3 == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
"Normal" JavaScript:
myArr.reduce(function (rows, key, index) {
return (index % 3 == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows;
}, []);
You can change the 3 to whatever you want the number of columns to be, or better yet, put it in a reusable function:
ECMAScript 6 style:
const toMatrix = (arr, width) =>
arr.reduce((rows, key, index) => (index % width == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
"Normal" JavaScript:
function toMatrix(arr, width) {
return arr.reduce(function (rows, key, index) {
return (index % width == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows;
}, []);
}
This code is generic no need to worry about size and array, works universally
function TwoDimensional(arr, size)
{
var res = [];
for(var i=0;i < arr.length;i = i+size)
res.push(arr.slice(i,i+size));
return res;
}
Defining empty array.
Iterate according to the size so we will get specified chunk.That's why I am incrementing i with size, because size can be 2,3,4,5,6......
Here, first I am slicing from i to (i+size) and then I am pushing it to empty array res.
Return the two-dimensional array.
The cleanest way I could come up with when stumbling across this myself was the following:
const arrayToMatrix = (array, columns) => Array(Math.ceil(array.length / columns)).fill('').reduce((acc, cur, index) => {
return [...acc, [...array].splice(index * columns, columns)]
}, [])
where usage would be something like
const things = [
'item 1', 'item 2',
'item 1', 'item 2',
'item 1', 'item 2'
]
const result = arrayToMatrix(things, 2)
where result ends up being
[
['item 1', 'item 2'],
['item 1', 'item 2'],
['item 1', 'item 2']
]
How about something like:
var matrixify = function(arr, rows, cols) {
var matrix = [];
if (rows * cols === arr.length) {
for(var i = 0; i < arr.length; i+= cols) {
matrix.push(arr.slice(i, cols + i));
}
}
return matrix;
};
var a = [0, 1, 2, 3, 4, 5, 6, 7];
matrixify(a, 2, 4);
http://jsfiddle.net/andrewwhitaker/ERAUs/
Simply use two for loops:
var rowNum = 3;
var colNum = 3;
var k = 0;
var dest = new Array(rowNum);
for (i=0; i<rowNum; ++i) {
var tmp = new Array(colNum);
for (j=0; j<colNum; ++j) {
tmp[j] = src[k];
k++;
}
dest[i] = tmp;
}
function matrixify( source, count )
{
var matrixified = [];
var tmp;
// iterate through the source array
for( var i = 0; i < source.length; i++ )
{
// use modulous to make sure you have the correct length.
if( i % count == 0 )
{
// if tmp exists, push it to the return array
if( tmp && tmp.length ) matrixified.push(tmp);
// reset the temporary array
tmp = [];
}
// add the current source value to the temp array.
tmp.push(source[i])
}
// return the result
return matrixified;
}
If you want to actually replace an array's internal values, I believe you can call the following:
source.splice(0, source.length, matrixify(source,3));
This a simple way to convert an array to a two-dimensional array.
function twoDarray(arr, totalPerArray) {
let i = 0;
let twoDimension = []; // Store the generated two D array
let tempArr = [...arr]; // Avoid modifying original array
while (i < arr.length) {
let subArray = []; // Store 2D subArray
for (var j = 0; j < totalPerArray; j++) {
if (tempArr.length) subArray.push(tempArr.shift());
}
twoDimension[twoDimension.length] = subArray;
i += totalPerArray;
}
return twoDimension;
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
twoDarray(arr, 3); // [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
function changeDimension(arr, size) {
var arrLen = arr.length;
var newArr = [];
var count=0;
var tempArr = [];
for(var i=0; i<arrLen; i++) {
count++;
tempArr.push(arr[i]);
if (count == size || i == arrLen-1) {
newArr.push(tempArr);
tempArr = [];
count = 0;
}
}
return newArr;
}
changeDimension([0, 1, 2, 3, 4, 5], 4);
function matrixify(array, n, m) {
var result = [];
for (var i = 0; i < n; i++) {
result[i] = array.splice(0, m);
}
return result;
}
a = matrixify(a, 3, 3);
function chunkArrToMultiDimArr(arr, size) {
var newArray = [];
while(arr.length > 0)
{
newArray.push(arr.slice(0, size));
arr = arr.slice(size);
}
return newArray;
}
//example - call function
chunkArrToMultiDimArr(["a", "b", "c", "d"], 2);
you can use push and slice like this
var array = [1,2,3,4,5,6,7,8,9] ;
var newarray = [[],[]] ;
newarray[0].push(array) ;
console.log(newarray[0]) ;
output will be
[[1, 2, 3, 4, 5, 6, 7, 8, 9]]
if you want divide array into 3 array
var array = [1,2,3,4,5,6,7,8,9] ;
var newarray = [[],[]] ;
newarray[0].push(array.slice(0,2)) ;
newarray[1].push(array.slice(3,5)) ;
newarray[2].push(array.slice(6,8)) ;
instead of three lines you can use splice
while(array.length) newarray.push(array.splice(0,3));
const x: any[] = ['abc', 'def', '532', '4ad', 'qwe', 'hf', 'fjgfj'];
// number of columns
const COL = 3;
const matrix = array.reduce((matrix, item, index) => {
if (index % COL === 0) {
matrix.push([]);
}
matrix[matrix.length - 1].push(item);
return matrix;
}, [])
console.log(matrix);
Using the Array grouping proposal (currently stage 3), you can now also do something like the following:
function chunkArray(array, perChunk) {
return Object.values(array.group((_, i) => i / perChunk | 0));
}
See also the MDN documentation for Array.prototype.group().
Simplest way with ES6 using Array.from()
const matrixify = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size));
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] ;
console.log(matrixify(list, 3));
Another stab at it,
Creating an empty matrix (Array of row arrays)
Iterating arr and assigning to matching rows
function arrayToMatrix(arr, wantedRows) {
// create a empty matrix (wantedRows Array of Arrays]
// with arr in scope
return new Array(wantedRows).fill(arr)
// replace with the next row from arr
.map(() => arr.splice(0, wantedRows))
}
// Initialize arr
arr = new Array(16).fill(0).map((val, i) => i)
// call!!
console.log(arrayToMatrix(arr, 4));
// Trying to make it nice
const arrToMat = (arr, wantedRows) => new Array(wantedRows).fill(arr)
.map(() => arr.splice(0, wantedRows))
(like in: this one)
(and: this one from other thread)
MatArray Class?
Extending an Array to add to a prototype, seems useful, it does need some features to complement the Array methods, maybe there is a case for a kind of MatArray Class? also for multidimensional mats and flattening them, maybe, maybe not..
1D Array convert 2D array via rows number:
function twoDimensional(array, row) {
let newArray = [];
let arraySize = Math.floor(array.length / row);
let extraArraySize = array.length % row;
while (array.length) {
if (!!extraArraySize) {
newArray.push(array.splice(0, arraySize + 1));
extraArraySize--;
} else {
newArray.push(array.splice(0, arraySize));
}
}
return newArray;
}
function twoDimensional(array, row) {
let newArray = [];
let arraySize = Math.floor(array.length / row);
let extraArraySize = array.length % row;
while (array.length) {
if (!!extraArraySize) {
newArray.push(array.splice(0, arraySize + 1));
extraArraySize--;
} else {
newArray.push(array.splice(0, arraySize));
}
}
return newArray;
}
console.log(twoDimensional([1,2,3,4,5,6,7,8,9,10,11,12,13,14], 3))
Short answer use:
const gridArray=(a,b)=>{const d=[];return a.forEach((e,f)=>{const
h=Math.floor(f/b);d[h]=d[h]||[],d[h][f%b]=a[f]}),d};
Where:
a: is the array
b: is the number of columns
An awesome repository here .
api : masfufa.js
sample : masfufa.html
According to that sample , the following snippet resolve the issue :
jsdk.getAPI('my');
var A=[1, 2, 3, 4, 5, 6, 7, 8, 9];
var MX=myAPI.getInstance('masfufa',{data:A,dim:'3x3'});
then :
MX.get[0][0] // -> 1 (first)
MX.get[2][2] // ->9 (last)
I'm trying to find all values in an array that would form a chain of incremented values - all referencing back to a certain starting value. Increments can go both "up" and "down".
array = [10, 2, 3, 5, 9, 11]
Starting with the number 2 should return:
[2, 3]
Starting with the number 10 should return:
[9, 10, 11]
There are of course plenty of inefficient ways of doing this, but I'm asking this here because doing this efficiently is important for my case and I'm such a JS newbie.
You can use Array.prototype.includes() to check if a number exists in an array. If the number is before the base reference add it using unshift, if after add it using push:
var array = [10, 2, 3, 5, 9, 11];
function findChain(array, num) {
if(!array.includes(num)) {
return [];
}
const result = [num];
let before = num - 1;
let after = num + 1;
while(array.includes(before)) {
result.unshift(before--);
}
while(array.includes(after)) {
result.push(after++);
}
return result;
}
console.log('Ref 2 -', findChain(array, 2));
console.log('Ref 5 -', findChain(array, 5));
console.log('Ref 10 -', findChain(array, 10));
console.log('Ref 20 -', findChain(array, 20));
A quick solution :
var array = [10, 2, 3, 5, 9, 11, 14, 89, 12, 8];
var trouver = nombre => {
var result = [];
if (array.indexOf(nombre) !== -1) result.push(nombre);
else return result;
for(var chiffre = nombre+1; array.indexOf(chiffre) !== -1; chiffre++) result.push(chiffre);
for(var chiffre = nombre-1; array.indexOf(chiffre) !== -1; chiffre--) result.push(chiffre);
return result.sort((a,b) => a-b);
}
console.log(trouver(9)); //[ 8, 9, 10, 11, 12 ]
Another solution could be a double chained list for it.
function getValues(array, value) {
var object = Object.create(null),
result,
o;
array.forEach(function (a) {
object[a] = object[a] || { value: a, pre: object[a - 1] || null, succ: object[a + 1] || null };
if (object[a - 1]) {
object[a - 1].succ = object[a];
}
if (object[a + 1]) {
object[a + 1].pre = object[a];
}
});
o = object[value];
if (o) {
result = [];
while (o.pre) {
o = o.pre;
}
while (o.succ) {
result.push(o.value);
o = o.succ;
}
result.push(o.value);
}
return result;
}
var array = [10, 2, 3, 5, 9, 11, 14, 89, 12, 8];
console.log(getValues(array, 2));
console.log(getValues(array, 10));
console.log(getValues(array, 42));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this approach
Sort the array first
Iterate array items one by one, keep pushing the start-counter if current-item value is not bigger than last-item by 1, else reset the start-counter to current-index.
For Example :
var arr = [10, 2, 3, 5, 9, 11];
function getAllSequences(arr) {
arr.sort(function(a, b) {
return a - b
});
var startIndex = 0;
var endIndex = 0;
var lastItem = 0;
var chains = [];
arr.forEach(function(item, index) {
if (index > 0) {
if ((item - lastItem) > 1) {
extractChain(chains, arr, startIndex, endIndex);
startIndex = index;
} else {
endIndex = index;
if (index == arr.length - 1) {
extractChain(chains, arr, startIndex, endIndex);
}
}
}
lastItem = item;
});
return chains;
}
console.log(getAllSequences(arr));
function extractChain(chains, arr, startIndex, endIndex) {
var value = arr.slice(startIndex, endIndex + 1);
if (value.length > 0) {
chains.push(value);
}
}
I need to get the sum of array items that are equal to the target. If the sum of array item will not equal to the target I would like to get the highest sum that is less than the target.
Here is an example:
Input: [4, 6, 8, 12, 4, 6, 6, 12, 4, 4,4]
Results:
[12]
[12]
[8, 4]
[6, 6]
[4,4,4]
[6,4]
Note: The array item can only be used once.
Currently here is what I have right now:
var subset_sum = function (items, target) {
var results = [];
items.sort(function (a, b) { return b - a });
ss = function (items) {
var item = items.shift();
if (item < target) {
var perms = [];
perms.push(item);
var isItemPush = false;
var counter = 0
var innerSubset = function () {
if (item + items[counter] === target) {
perms.push(items[counter])
items.splice(counter, 1);
results.push(perms);
isItemPush = true;
} else {
if (counter < items.length) {
counter += 1;
innerSubset();
}
}
}
innerSubset();
} else {
results.push(item);
}
if (items.length === 0) {
return results;
}
return ss(items);
}
return ss(items)
}
window.onload = function () {
var items = [4, 6, 8, 12, 4, 6, 6, 12, 4, 4];
target = 12;
result = subset_sum(items, target);
console.log(result);
}
The problem with this approach is that it is only one or two dimensional. From the example above, it does not return the result [4,4,4] and 6.
Very similar solution to yours, a bit unclear if it's helpful:
numbers = [4, 6, 8, 12, 4, 6, 6, 12, 4, 4];
var result = createSubsets(numbers, 12);
console.log('Result', JSON.stringify(result));
function createSubsets(numbers, target) {
// filter out all items larger than target
numbers = numbers.filter(function (value) {
return value <= target;
});
// sort from largest to smallest
numbers.sort(function (a, b) {
return b - a;
});
// array with all the subsets
var result = [];
while (numbers.length > 0) {
var i;
var sum = 0;
var addedIndices = [];
// go from the largest to the smallest number and
// add as many of them as long as the sum isn't above target
for (i = 0; i < numbers.length; i++) {
if (sum + numbers[i] <= target) {
sum += numbers[i];
addedIndices.push(i);
}
}
// remove the items we summed up from the numbers array, and store the items to result
// since we're going to splice the numbers array several times we start with the largest index
// and go to the smallest to not affect index position with splice.
var subset = [];
for (i = addedIndices.length - 1; i >= 0; i--) {
subset.unshift(numbers[addedIndices[i]]);
numbers.splice(addedIndices[i], 1);
}
result.push(subset);
}
return result;
}
Produces array:
[12],[12],[8,4],[6,6],[6,4],[4,4]
There's no limit regarding the subset length. If you add one more 4 to the numbers array you will get result:
[12],[12],[8,4],[6,6],[6,4],[4,4,4]
JSFiddle: http://jsfiddle.net/kUELD/