I have:
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
array2 = ['a', 'b', 'c'];
I got the concat of arrays working, but only one at a time:
var alternatingArrayResult = [array1, array2].reduce(function (r, a) {
return a.forEach(function (a, i) {
return (r[i] = r[i] || []).push(a);
}), r;
}, []).reduce(function (a, b) {
return a.concat(b);
});
// => alternatingArrayResult = [1, 'a', 2, 'b', 3, 'c', 4, 5, 6, 7, 8, 9];
I want to add two items from array 1, then one from array 2 - and so on.
Desired output:
result = [1, 2, 'a', 3, 4, 'b', 5, 6, 'c', 7, 8, 9];
var array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array2 = ['a', 'b', 'c'];
var alternatingResultArray = [array1, array2].reduce(function (r, a) {
return a.forEach(function (a, i) {
return (r[i] = r[i] || []).push(a);
}), r;
}, []).reduce(function (a, b) {
return a.concat(b);
});
console.log(alternatingResultArray);
You could get a lenght and iterate the parts for pushing.
const
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
array2 = ['a', 'b', 'c'],
result = [];
for (i = 0, l = Math.max(Math.ceil(array1.length / 2), array2.length); i < l; i++) {
result.push(
...array1.slice(i * 2, (i + 1) * 2),
...array2.slice(i, i + 1),
);
}
console.log(...result);
A more abstact version with size of the wanted subarrays.
const
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
array2 = ['a', 'b', 'c'],
data = [array1, array2],
sizes = [2, 1]
result = [];
for (i = 0, l = Math.max(...data.map(({ length }, i) => Math.ceil(length / sizes[i]))); i < l; i++) {
data.forEach((a, j) => result.push(...a.slice(i * sizes[j], (i + 1) * sizes[j])));
}
console.log(...result);
Use Array.map with a thisArg for the desired result (see MDN).
thisArg (Optional) Value to use as this when executing callback.
let array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let array2 = ['a', 'b', 'c'];
let arrayConcatted = array1
.flatMap( function(v, i) {
// ^ not arrow to keep thisArg in scope
const arr2Value = i && i % 2 === 0 && this.length && this.shift();
return arr2Value ? [arr2Value, v] : v;
}, array2.slice())
// ^ 'this', a copy of array2
console.log(JSON.stringify(arrayConcatted));
// IE
var arrConcatIE = [];
var arr2Clone = array2.slice();
for (var i=0; i < array1.length; i +=1) {
const arr2Value = i && i % 2 === 0 && arr2Clone.length && arr2Clone.shift();
if (arr2Value) {
arrConcatIE.push(arr2Value);
}
arrConcatIE.push(array1[i]);
}
console.log(JSON.stringify(arrConcatIE));
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]), [])
);
});
Is there a better way to do this? Faster or more readable? Please share your approach.
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
// expected output [0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]
You could iterate the array by the minimum of both array lengths and take the rest by slicing the arrays from the minimum length.
function merge(a, b) {
const
result = [];
l = Math.min(a.length, b.length);
for (let i = 0; i < l; i++) result.push(a[i], b[i]);
result.push(...a.slice(l), ...b.slice(l));
return result;
}
console.log(...merge([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], ['a', 'b', 'c', 'd', 'e', 'f']));
You can use either recursion:
const Nil =
Symbol();
const intercalate =
([x=Nil, ...xn], [y=Nil, ...yn], ret=[]) =>
x === Nil && y === Nil
? ret
: intercalate(xn, yn, ret.concat( x === Nil ? [] : x
, y === Nil ? [] : y
));
Or Array#flatMap:
const intercalate =
(xn, yn) =>
xn.flatMap((x, i) =>
i >= yn.length
? [x]
: [x, yn[i]]);
My approach:
function mergeBetween(a, b) {
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
return a
}
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
mergeBetween(a, b) //[0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]
This would be my approach, if speed is your game, then you should stick to for loops... But I would suggest avoiding premature optimization in general... Not sure if that is what you meant by "faster" either...
const a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const b = ["a", "b", "c", "d", "e", "f"];
// check which is longer
const longer = a.length > b.length ? a : b;
const shorter = a.length < b.length ? a : b;
// declare a new variable to hold the combined array
let newArray = [];
for (let i = 0; i < longer.length; i++)
newArray =
i < shorter.length
? [...newArray, longer[i], shorter[i]]
: [...newArray, longer[i]];
console.log(newArray)
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);
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);
I have two arrays:
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
Using arr1 as the baseline, arr2 does not match because it contains three 1's whereas arr1 only has two. arr3, however should return true because it has elements from arr1.
I tried
if(_.difference(arr2, arr1).length === 0)
But this does not take into account the number of occurrences
You could count all value from the first array and iterate the second with every and return early if a value is not given or zero, otherwise decrement the count and go on.
function check(a, b) {
var count = a.reduce((o, v) => (o[v] = (o[v] || 0) + 1, o), {});
return b.every(v => count[v] && count[v]--);
}
var arr1 = [1, 2, 3, 1, 2, 3, 4],
arr2 = [1, 3, 1, 1],
arr3 = [1, 1, 2, 2, 3];
console.log(check(arr1, arr2)); // false
console.log(check(arr1, arr3)); // true
You can try to loop through second array and compare t against main array if value found make main array cell to false and set flag as true
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
function checkArray(compareMe, toThis){
var flag = false;
for(var i = 0; i < toThis.length; i++){
flag = false;
for(var j = 0; j < compareMe.length; j++){
if(compareMe[j] == toThis[i]){
compareMe[j] = false;
flag = true;
break;
}
}
}
return flag;
}
console.log(checkArray(arr1, arr2));
console.log(checkArray(arr1, arr3));
Try this solution:
const arr1 = [1, 2, 3, 1, 2, 3, 4],
arr2 = [1, 3, 1, 1],
arr3 = [1, 1, 2, 2, 3],
arr4 = [1, 2, 3, 1, 2, 3, 4, 1];
function containsFn(src, trg) {
const srcCp = src.slice();
for(let i = 0; i < trg.length; i++) {
const index = srcCp.indexOf(trg[i]);
if(index > - 1) {
srcCp.splice(index, 1);
} else {
return false;
}
}
return true;
}
console.log(containsFn(arr1, arr2));
console.log(containsFn(arr1, arr3));
console.log(containsFn(arr1, arr4));
Looks like I'm already late to the party but this would be a recursive solution:
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
function findAllIn(find, search) {
if (find.length == 0) {
return true;
}
i = search.indexOf(find[0]);
if (i == -1) {
return false;
}
return findAllIn(find.slice(1,find.length), search.slice(0,i).concat(search.slice(i+1, search.length)));
}
console.log(findAllIn(arr2, arr1)); // false
console.log(findAllIn(arr3, arr1)); // true
This should do the trick
Not efficient but I think it is easy to understand
const count = (x, xs) =>
xs.reduce((y, xi) => y + (xi === x ? 1 : 0), 0)
const isInclusive = (xs, ys) =>
xs.every((xi) => count(xi, xs) >= count(xi, ys))
const arr1 = [1, 2, 3, 1, 2, 3, 4]
const arr2 = [1, 3, 1, 1]
const arr3 = [1, 1, 2, 2, 3]
console.log(isInclusive(arr1, arr2))
console.log(isInclusive(arr1, arr3))
Based on this answer: https://stackoverflow.com/a/4026828/3838031
You can do this:
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
console.log((arr1.diff(arr2).length === 0) ? "True" : "False");
console.log((arr1.diff(arr3).length === 0) ? "True" : "False");
console.log((arr2.diff(arr1).length === 0) ? "True" : "False");
console.log((arr2.diff(arr3).length === 0) ? "True" : "False");
console.log((arr3.diff(arr1).length === 0) ? "True" : "False");
console.log((arr3.diff(arr2).length === 0) ? "True" : "False");