Related
I'm trying to find the smallest common multiple from one array by comparing it to the values in the other by using % num === 0. The answer should be 6, but because each number in the first array is true at least once, they all get returned. How do I find the value that is only true and never false?
let arr = [1, 2, 3]
function test(arr) {
let x = [1, 2, 3, 4, 5, 6, 7, 8]
for (let n of arr) {
return x.filter(k => k % n === 0)
}
}
console.log(test(arr))
You need loop over the x array and return the first element that gets divided by every value in arr.
let arr = [1, 2, 3];
function test(arr) {
let x = [1, 2, 3, 4, 5, 6, 7, 8];
for (let n of x) {
if (arr.every((a) => n % a === 0)) {
return n;
}
}
}
console.log(test(arr));
You can also simply the solution using Array.prototype.find.
const
arr = [1, 2, 3],
test = (arr) =>
[1, 2, 3, 4, 5, 6, 7, 8].find((n) => arr.every((a) => n % a === 0));
console.log(test(arr));
Note: If x is not sorted, then you will have to sort it first.
const arr = [1, 2, 3],
test = (arr) =>
[8, 7, 6, 5, 4, 3, 2, 1]
.sort((a, b) => a - b)
.find((n) => arr.every((a) => n % a === 0));
console.log(test(arr));
Update based on OP's comment
You can use Array.prototype.filter and Array.prototype.some.
const arr = [1, 2, 3],
test = (arr) =>
[1, 2, 3, 4, 5, 6, 7, 8].filter((n) => arr.some((a) => n / a === 2));
console.log(test(arr));
If x is sorted can use find and every
let arr = [1, 2, 3]
let x = [1, 2, 3, 4, 5, 6, 7, 8, 12]
let res = x.find(n => arr.every(a => n%a === 0))
console.log(res)
if unsorted x
let arr = [1, 2, 3]
let x = [1, 12, 6, 4, 2, 7, 8]
let res = [...x].sort((a,b)=> a-b).find(n => arr.every(a => n%a === 0))
console.log(res)
Filter and intersect
let arr = [1, 2, 3]
let x = [1, 2, 3, 4, 5, 6, 7, 8]
function test(arr) {
let common = []
arr.forEach(n => common.push(x.filter(k => k % n === 0)))
return common.reduce((acc, cur) => acc.filter(e => cur.includes(e)));
}
console.log(test(arr))
Late to the party answer
You could solved this with one line of code using Array.reduce. Here we initialize it with an empty array and then use a ternary operator to append values that pass the remainder test. Note that we don't need to check for zero (c % n === 0) because we treat the result as a boolean.
x.reduce((p,c) => c % n ? p : p.concat([c]), [])
// TEST
const x = [1, 2, 3, 4, 5, 6, 7, 8];
[1, 2, 3].forEach(n => {
console.log(
"n =" + n,
x.reduce((p,c) => c % n ? p : p.concat([c]), [])
);
});
My input is an array like so:
[7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7]
I want to group together the numbers and add them, but by neighbors, not by total in the array. So the output would be:
['7:4', '4:2', '5:3', 1, 9, 2, '7:2']
I've attempted a few different methods using reduce, and gotten close but using the built-in Javascript methods I end up counting ALL in the array, not by neighbors.
const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
const masterArray = [];
const unique = new Set (numberArray); // Set {7, 4, 5, 1, 9, 2, 7}
unique.forEach(u => {
masterArray.push(numberArray.filter(e => e === u));
});
console.log(masterArray);
Set is obviously wrong to use here because that gets the unique values and counts them, but I want to do it by neighbor only. So then I think I should be using a reduce but I run into the same problem.
var test = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
console.log(
test.reduce((acc, element) => {
if (acc.length && acc[acc.length - 1].key == element) {
acc[acc.length - 1].count++;
} else {
acc.push({ key: element, count: 1 });
}
return acc;
}, []).map(element => `${element.key}:${element.count}`)
);
So the logic first reduces the number to an array, tracking the last key and count. So long as the key is the same, the count is incremented. Once the key changes, a new object is pushed to start the next run. After the reduce is done, a map is performed to convert the key and counts into the desired strings.
You'll need to keep track of the last number iterated over in a persistent variable, as well as the number of occurrences of the last number which gets incremented:
const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
let lastNum = arr[0];
let count = 0;
const results = [];
const doPush = () => {
results.push(
count === 1
? lastNum
: `${lastNum}:${count}`
);
};
for (const num of arr) {
if (num !== lastNum) {
doPush();
lastNum = num;
count = 1;
} else count++;
}
doPush();
console.log(results);
You could reduce the array by having a look to the last value a the index before the actual value.
const
array = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
result = array.reduce((r, value, i, { [i - 1]: last }) => {
let count = 0;
if (last === value) count = (+r.pop().toString().split(':')[1] || 0) + 1;
return [...r, count ? `${value}:${count}`: value];
}, []);
console.log(result);
Here is a solution that uses a recursive function to group the neighbors, and then Array.prototype.map() to format with a colon:
const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
output = (function groupNeighbors([first, ...rest], output = [], last) {
last === first ? output[output.length - 1].push(first) : output.push([first]);
return rest.length ? groupNeighbors(rest, output, first) : output;
})(arr).map(({ [0]: num, length }) => length > 1 ? [num, length].join(':') : num);
console.log(output);
As it uses recursion, it is limited in terms of input array length, you can find the stack size limits per browser here: Browser Javascript Stack size limit
Variant with Array.prototype.reduce() (slightly shortest, no recursion, unlimited input length):
const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
output = arr
.reduce(
(acc, cur, i, { [i - 1]: last }) =>
(cur === last ? acc[acc.length - 1].push(cur) : acc.push([cur])) && acc,
[]
)
.map(({ [0]: num, length }) => length > 1 ? [num, length].join(':') : num);
console.log(output);
Yes, the proper choice here is reduce:
const countDuplicatesQuantity = (arr) => {
const duplicatesObj = arr.reduce((duplicates, item) => {
duplicates[item] = duplicates[item] ? duplicates[item] + 1 : 1;
return duplicates;
}, {});
return Object.keys(duplicatesObj).map(
(key) => `${key}:${duplicatesObj[key]}`,
);
};
You wanted reduce, how about twice? :) (I don't know if I've done something stupid here.)
First reduce finds where the values change in the array, second uses that to build new array.
const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
const masterArray = firstArray
.reduce((acc, v, i, all) => all[i + 1] !== v ? acc.concat(i) : acc, [])
.reduce(
(acc, v, i, all) => {
const range = v - (i === 0 ? -1 : all[i - 1]);
return acc.concat(range > 1 ? firstArray[v] + ':' + range : firstArray[v]);
}, []
);
console.log(masterArray);
Using array.reduce:
const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
var newArray = [];
var count = 0;
firstArray.reduce((acc, cur, index) => {
if (acc == cur) {
count++;
}
if (acc != cur || index+1 == firstArray.length) {
newArray.push(acc + ":" + count);
count=1
}
return cur;
})
console.log(newArray);
my way ... I felt that there could be "simpler"
const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
const result = firstArray.reduceRight((r,v)=>
{
let [n,c] = !r.length ? [-v,0] : isNaN(r[0]) ? r[0].split(':') : [r[0],1]
if (n==v) r[0] = `${n}:${++c}`
else r.unshift(v)
return r
},[])
console.log( JSON.stringify(result) )
// [ "7:4", "4:2", "5:3", 1, 9, 2, "7:2" ]
.as-console-wrapper { max-height: 100% !important; top: 0; }
I couldn't find an answer to this specific question on S.O.
Let's say I have an array of strings, or in this case, numbers:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
I'd like the output to be:
var output = [[1,1,1], [2], [3,3,3,3,3], [4], [5, 5, 5]];
I was hoping to use Lodash but most of that stuff tends to remove duplicates rather chunk them together into their own array. Maybe some kind of .map iterator?
The order of the output doesn't really matter so much. It just needs to chunk the duplicates into separate arrays that I'd like to keep.
You can use reduce to group the array elements into an object. Use Object.values to convert the object into an array.
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => {
(c[v] = c[v] || []).push(v);
return c;
}, {}));
console.log(result);
Shorter version:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => ((c[v] = c[v] || []).push(v), c), {}));
console.log(result);
You can do this with Array.reduce in a concise way like this:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = x.reduce((r,c) => (r[c] = [...(r[c] || []), c],r), {})
console.log(Object.values(result))
The exact same with lodash would be:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = _.values(_.groupBy(x))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Using _.values to extract the values of the grouping object and _.groupBy to get the actual groupings
Use Array#prototype#reduce to group them:
const x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let helperObj = {};
const res = x.reduce((acc, curr) => {
// If key is not present then add it
if (!helperObj[curr]) {
helperObj[curr] = curr;
acc.push([curr]);
}
// Else find the index and push it
else {
let index = acc.findIndex(x => x[0] === curr);
if (index !== -1) {
acc[index].push(curr);
}
}
return acc;
}, []);
console.log(res);
Since you're hoping to use Lodash, you might be interested in groupBy. It returns on object, but the _.values will give you the nested array:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let groups = _.values(_.groupBy(x))
console.log(groups)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here's an imperative solution:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
x.sort();
var res = [];
for (const [i, n] of x.entries()) {
if (n !== x[i-1]) res.push([n]);
else res[res.length-1].push(n);
}
console.log(res);
I would like to interleave two arrays, BUT only return pairs when a certain condition is met. As an example:
first_array = [1, 2, 3, 4, 5, 6, 7, 8];
second_array = [, , , , 1, , 0, 1];
I need to return ONLY pairs where array-2 is non-null, in other words, the output I need is:
interleaved = [5, 1, 7, 0, 8, 1];
I have an interleave function that works:
function send_values() {
let interleaved = [];
for (let i = 0; i < first_array.length; i++) {
interleaved.push(first_array[i], second_array[i]);
}
}
...but the output is, obviously:
interleaved = [1, , 2, , 3, , 4, , 5, 1, 6, , 7, 0, 8, 1];
...which is not what I need. Suggestions?
You could iterate the sparse array and take only the values with the values at the same index from array one.
var array1 = [1, 2, 3, 4, 5, 6, 7, 8],
array2 = [, , , , 1, , 0, 1],
result = array2.reduce((r, v, i) => r.concat(array1[i], v), []);
console.log(result);
Here's a generic functional solution:
pairs = (a, b) => a.map((_, i) => [a[i], b[i]])
flat = a => [].concat(...a)
valid = x => x === 0 || Boolean(x)
array_1 = [1, 2, 3, 4, 5, 6, 7, 8];
array_2 = [ , , , , 1, , 0, 1];
result = flat(
pairs(array_1, array_2)
.filter(x => x.every(valid))
)
console.log(result)
Works both ways, that is, it doesn't matter which array contains the null values. Also, you can redefine valid if there are other things to exclude.
As a bonus, if you replace pairs with zip, you can make it work for any number of arrays.
So I have an array of ids something like this:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
I need a function that will be called like mergeArray(arr, 3), and it should return comma separated values with maximum of 3 elements like this:
const newArr = ['1,2,3', '4,5,6', '7,8,9', '10,11'];
How can I do this? If possible with ES6 functions for simpler code.
slice your array into 3 lengths arrays and directly join them
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const mergeArray = (arr, size) => {
let res = [];
for (i = 0; i < arr.length; i += size) {
res.push(arr.slice(i, i + size).join(','));
}
return res;
}
console.log(mergeArray(arr, 3));
You can split() the array into the specific size and join() them before pushing into the resulting array:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var i, j, newArr=[], size = 3;
for (i=0,j=arr.length; i<j; i+=size) {
newArr.push(arr.slice(i, i+size).join());
}
console.log(newArr);
One of the ways to do it is with Array.prototype.reduce and Array.prototype.map:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function mergeArray(arr, n) {
return arr
.reduce((all, el, i) => {
const ind = Math.floor(i/n);
all[ind] = [...all[ind] || [], el]
return all;
},[])
.map(a => a.join(','))
}
console.log(mergeArray(arr, 3));
You could join the array and match the wanted parts with a regular expression.
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
result = data.join(',').match(/\d+(,\d+(,\d+)?)?/g)
console.log(result);