Creating an array from another array - javascript

I'm learning Javascript and I'm wondering what the most elegant way to convert this: [1,8]
into this:[1,2,3,4,5,6,7,8]?
Thanks a lot!

const argarray = [1, 8]
const countToN = (array) => {
// init results array
let res = []
// start at the first value array[0] go *up to* the second array[1]
for (let i = array[0]; i <= array[1]; i++) {
res.push(i)
}
// return the result
return res
}
console.log(countToN([1, 10]))
This would accommodate what you're trying to do, but it's fairly brittle. You'd have to check that it's an array and that it has only 2 values. If you had other requirements, I could amend this to account for it.

Here's a solution without loops. Note that this only works with positive numbers. It supports arrays of any length, but will always base the result off of the first and last values.
const case1 = [1, 8];
const case2 = [5, 20];
const startToEnd = (array) => {
const last = array[array.length - 1];
const newArray = [...Array(last + 1).keys()];
return newArray.slice(array[0], last + 1);
};
console.log(startToEnd(case1));
console.log(startToEnd(case2));
Here's a solution that works for negative values as well:
const case1 = [-5, 30];
const case2 = [-20, -10];
const case3 = [9, 14];
const startToEndSolid = (array) => {
const length = array[array.length - 1] - array[0] + 1;
if (length < 0) throw new Error('Last value must be greater than the first value.');
return Array.from(Array(length)).map((_, i) => array[0] + i);
};
console.log(startToEndSolid(case1));
console.log(startToEndSolid(case2));
console.log(startToEndSolid(case3));

A simple for loop will do it. Here's an example that has error checking and allows you to range both backwards and forwards (ie [1, 8], and also [1, -8]).
function range(arr) {
// Check if the argument (if there is one) is
// an array, and if it's an array it has a length of
// of two. If not return an error message.
if (!Array.isArray(arr) || arr.length !== 2) {
return 'Not possible';
}
// Deconstruct the first and last elements
// from the array
const [ first, last ] = arr;
// Create a new array to capture the range
const out = [];
// If the last integer is greater than the first
// integer walk the loop forwards
if (last > first) {
for (let i = first; i <= last; i++) {
out.push(i);
}
// Otherwise walk the loop backwards
} else {
for (let i = first; i >= last; i--) {
out.push(i);
}
}
// Finally return the array
return out;
}
console.log(range([1, 8]));
console.log(range('18'));
console.log(range());
console.log(range([1]));
console.log(range([-3, 6]));
console.log(range([9, 16, 23]));
console.log(range([4, -4]));
console.log(range([1, -8, 12]));
console.log(range(null));
console.log(range(undefined));
console.log(range([4, 4]));
Additional documentation
Destructuring assignment

Use Array#map as follows:
const input = [1,8],
output = [...Array(input[1] - input[0] + 1)]
.map((_,i) => input[0] + i);
console.log( output );

Related

Reverse array in-place using split-merge method

I am trying to reverse an array in JS in-place (without using extra array).
I am using split-merge recursively (I first split the array into two halves and then rearrange each half separately and after that combine the results of the two arrangements).
the problem seems to arise if the array length is an odd number, in which case there will exist an array that have a single item and another array that have two items.
example :
reverseArrayInPlace([1, 5, 0, 4, 6])
should work like this :
1- reverseArrayInPlace([1,5,0]) -> returns the below calls
reverseArrayInPlace([1, 5]) -> returns [5, 1]
reverseArrayInPlace([0]) -> returns [0]
now the two arrays of the first call should be merged and swapped. The result should be [0,5,1]
2- reverseArrayInPlace([4, 6]) -> returns [6,4]
Now, the result of the call (1) and call (2) must be merged and swapped (using concat also);
which will make the result as : [6,4,0,5,1].
I know there are other easier ways, but I want to know why my code is not returning the correct value .
let reverseArrayInPlace = ar => {
let splitArray = arr => {
if( arr.length === 1){
console.log('length = 1', arr);
return arr;
}
else if(arr.length === 2){
console.log('length = 2', arr);
let temp = arr[0]; arr[0] = arr[1]; arr[1] = temp;
return arr;
}
else{
reverseArrayInPlace(arr);
//reverseArrayInPlace (ar2);
}
}
let mergeArray = (arr1, arr2) => {
console.log("Swapping : ", arr1, arr2);
console.log('Concated : ',arr2.concat(arr1));
if(arr1 === undefined)
return arr2;
else if(arr2 === undefined)
return arr1;
else
return arr2.concat(arr1);
}
let half = Math.ceil(ar.length / 2);
//console.log('half = ', half);
ar1 = splitArray(ar.slice(0, half));
ar2 = splitArray(ar.slice(half));
//console.log(arr1, arr2);
return mergeArray(ar1, ar2);
}
let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));
In your split array function, you miss a return:
let splitArray = arr => {
if( arr.length === 1){
console.log('length = 1', arr);
return arr;
}
else if(arr.length === 2){
console.log('length = 2', arr);
let temp = arr[0]; arr[0] = arr[1]; arr[1] = temp;
return arr;
}
else{
***RETURN*** reverseArrayInPlace(arr);
//reverseArrayInPlace (ar2);
}
}
I used debugger in chrome navigateur to go step by step and noticed that ar1 was null on your step 1- reverseArrayInPlace([1,5,0]) -> returns the below calls
So the result contains only the second part: the reversed second array [6,4]
The missing return statement is the initial problem, but more broadly speaking, this is not a true inplace algorithm, because it still reserves O(n) auxiliary memory by creating new arrays.
For an algorithm to be inplace, there should be no O(n) auxiliary memory usage. Instead make also the splitArray and mergeArray inplace functions, so that at all times there is only one array that is being mutated.
For that to happen, you would need to pass the start/end indices of the subarray that is going to be subject of the split/merge operation.
It is also safer to include the empty-array case in the first base case of splitArray: so use <= 1 instead of === 1.
Here is your code altered with that idea:
let reverseArrayInPlace = (arr, start=0, end=ar.length) => {
let splitArray = (start, end) => {
if (end - start <= 1) return;
if (end - start === 2) {
let temp = arr[start]; arr[start] = arr[start+1]; arr[start+1] = temp;
}
else{
reverseArrayInPlace(arr, start, end);
}
}
let mergeArray = (start, mid, end) => {
arr.splice(start, 0, ...arr.splice(mid, end - mid));
}
let half = (start + end) >> 1;
splitArray(start, half);
splitArray(half, end);
mergeArray(start, half, end);
return arr;
}
let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));
You also don't really need to deal with the second base case separately. The operation will work fine if you deal with that case as a recursive case.
Here is your code altered with that idea:
let reverseArrayInPlace = (arr, start=0, end=ar.length) => {
let splitArray = (start, end) => {
if (end - start > 1) reverseArrayInPlace(arr, start, end);
}
let mergeArray = (start, mid, end) => {
arr.splice(start, 0, ...arr.splice(mid, end - mid));
}
let half = (start + end) >> 1;
splitArray(start, half);
splitArray(half, end);
mergeArray(start, half, end);
return arr;
}
let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));

How can I subtract numbers from array in JavaScript?

For example: [5, 4, 1] = 0
If it is easy question, I'm so sorry, but I'm new in JavaScript! Thanks from all answers
Use Array.prototype.reduce to reduce and Array to a single output:
const numbers = [5, 4, 1];
const sub = numbers.reduce((acc, num) => acc - num);
console.log(sub) // 0
Using a for loop and if else:
const numbers = [5,4,1] ;
let ans = 0; //Initialize ans with some value
if(numbers.length > 0) ans = numbers[0]; //If array has length >0, use the first value. This will let you handle single length arrays
for(let i = 1; i < numbers.length;i++){
ans -= numbers[i]; //subtract for every other element
}
console.log(ans);
You can take a look on Array.reduce function on mozilla docs.
const subtractNumbersFromArray = (arr) => {
return arr.reduce((acc, currentValue) => acc - currentValue);
};
const result = subtractNumbersFromArray([5, 4, 1]) // 0
const result = subtractNumbersFromArray([10, 3, 2]) // 5

How do I sum the elements of an arbitrary number of arrays with different lengths in Javascript?

While the code below will satisfy adding two arrays with different lengths, how can I modify this to accept an arbitrary number of arrays as arguments so that, for example, ([1, 2, 3], [4, 5], [6]) will return an array of [11, 7, 3] ?
const addTogether = (arr1, arr2) => {
let result = [];
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
result.push((arr1[i] || 0) + (arr2[i] || 0))
}
return result
}
Use a nested array, and loop over the array rather than hard-coding two array variables.
You can use arrays.map() to get all the lengths so you can calculate the maximum length. And arrays.reduce() to sum up an element in each array.
const addTogether = (...arrays) => {
let result = [];
let len = Math.max(...arrays.map(a => a.length));
for (let i = 0; i < len; i++) {
result.push(arrays.reduce((sum, arr) => sum + (arr[i] || 0), 0));
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]));
You can use arguments object inside function.
arguments is an Array-like object accessible inside functions that contains the values of the arguments passed to that function.
const addTogether = function () {
const inputs = [...arguments];
const maxLen = Math.max(...inputs.map((item) => item.length));
const result = [];
for (let i = 0; i < maxLen; i ++) {
result.push(inputs.reduce((acc, cur) => acc + (cur[i] || 0), 0));
}
return result;
};
console.log(addTogether([1,2,3], [4,5], [6]));
Solution:
const addTogether = (...args) => {
let result = [];
let max = 0;
args.forEach((arg)=>{
max = Math.max(max,arg.length)
})
for(let j=0;j<max;j++){
result[j]= 0
for (let i = 0; i < args.length; i++) {
if(args[i][j])
result[j]+= args[i][j]
}
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]))
Output:[ 11, 7, 3 ]
Use rest param syntax to accept an arbitrary number of arguments. Sort the outer array by their length in descending order. By using destructuring assignment separate the first and rest of the inner arrays. At last use Array.prototype.map() to traverse the first array as it is the largest array and use Array.prototype.reduce() method to get the summation.
const addTogether = (...ar) => {
ar.sort((x, y) => y.length - x.length);
const [first, ...br] = ar;
return first.map(
(x, i) => x + br.reduce((p, c) => (i < c.length ? c[i] + p : p), 0)
);
};
console.log(addTogether([1, 2, 3], [4, 5], [6]));
Instead of using a for loop that requires you to know the lengths of each array, try using something that doesn't. For example - while loop.
Increment using a dummy variable and reset it for each array and set condition for loop termination as - arr[i] === null.

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

find intersection elements in arrays in an array

I need to construct a function intersection that compares input arrays and returns a new array with elements found in all of the inputs.
The following solution works if in each array the numbers only repeat once, otherwise it breaks. Also, I don't know how to simplify and not use messy for loops:
function intersection(arrayOfArrays) {
let joinedArray = [];
let reducedArray = [];
for (let iOuter in arrayOfArrays) {
for (let iInner in arrayOfArrays[iOuter]) {
joinedArray.push(arrayOfArrays[iOuter][iInner]);
}
return joinedArray;
}
for (let i in joinedArray.sort()) {
if (joinedArray[i] === joinedArray[ i - (arrayOfArrays.length - 1)]) {
reducedArray.push(joinedArray[i]);
}
}
return reducedArray;
}
Try thhis:-
function a1(ar,ar1){
x = new Set(ar)
y = new Set(ar1)
var result = []
for (let i of x){
if (y.has(i)){
result.push(i)
}
}
if (result){return result}
else{ return 0}
}
var a= [3,4,5,6]
var b = [8,5,6,1]
console.log(a1(a,b)) //output=> [5,6]
Hopefully this snippet will be useful
var a = [2, 3, 9];
var b = [2, 8, 9, 4, 1];
var c = [3, 4, 5, 1, 2, 1, 9];
var d = [1, 2]
function intersect() {
// create an empty array to store any input array,All the comparasion
// will be done against this one
var initialArray = [];
// Convert all the arguments object to array
// there can be n number of supplied input array
// sorting the array by it's length. the shortest array
//will have at least all the elements
var x = Array.prototype.slice.call(arguments).sort(function(a, b) {
return a.length - b.length
});
initialArray = x[0];
// loop over remaining array
for (var i = 1; i < x.length; i++) {
var tempArray = x[i];
// now check if every element of the initial array is present
// in rest of the arrays
initialArray.forEach(function(item, index) {
// if there is some element which is present in intial arrat but not in current array
// remove that eleemnt.
//because intersection requires element to present in all arrays
if (x[i].indexOf(item) === -1) {
initialArray.splice(index, 1)
}
})
}
return initialArray;
}
console.log(intersect(a, b, c, d))
There is a nice way of doing it using reduce to intersect through your array of arrays and then filter to make remaining values unique.
function intersection(arrayOfArrays) {
return arrayOfArrays
.reduce((acc,array,index) => { // Intersect arrays
if (index === 0)
return array;
return array.filter((value) => acc.includes(value));
}, [])
.filter((value, index, self) => self.indexOf(value) === index) // Make values unique
;
}
You can iterate through each array and count the frequency of occurrence of the number in an object where the key is the number in the array and its property being the array of occurrence in an array. Using the generated object find out the lowest frequency of each number and check if its value is more than zero and add that number to the result.
function intersection(arrayOfArrays) {
const frequency = arrayOfArrays.reduce((r, a, i) => {
a.forEach(v => {
if(!(v in r))
r[v] = Array.from({length:arrayOfArrays.length}).fill(0);
r[v][i] = r[v][i] + 1;
});
return r;
}, {});
return Object.keys(frequency).reduce((r,k) => {
const minCount = Math.min(...frequency[k]);
if(minCount) {
r = r.concat(Array.from({length: minCount}).fill(+k));
}
return r;
}, []);
}
console.log(intersection([[2,3, 45, 45, 5],[4,5,45, 45, 45, 6,7], [3, 7, 5,45, 45, 45, 45,7]]))

Categories

Resources