Related
function sumPairs(ints, s) {
let result = [];
for(let i = 0; i < ints.length; i++){
for(let j = 0; j < ints.slice(i); j++){
(ints[i] + ints[j] === s && result.length === 0) ? result.push(ints[i], ints[j]) : 0;
}
} return result;
}
sumPairs([1, 2, 3, 4, 5, 6], 10) //returns [6, 4] instead of [4,6]?
How do I fix this so that the function returns the first pair that add up to s, the second argument? I added the result.length === 0 condition in the if statement a further update would be prevented?
Just iterate over the array using for..of loop and use Set to achieve the desired result.
function sumPairs(ints, s) {
const dict = new Set();
for (let num of ints) {
if (dict.has(s - num)) return [s - num, num];
else dict.add(num);
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
Iterations:
Iteration 1 :=> num = 1 and dict is empty
dict doesn't have 9 (because of s - num i.e 10 - 1) so add num i.e 1 to dict.
Iteration 2 :=> num = 2 and dict has 1
dict doesn't have 8 (because of s - num i.e 10 - 2) so add num i.e 2 to dict
Iteration 3 :=> num = 3 and dict has 1, 2
dict doesn't have 7 (because of s - num i.e 10 - 3) so add num i.e 3 to dict
Iteration 4 :=> num = 4 and dict has 1, 2, 3
dict doesn't have 6 (because of s - num i.e 10 - 4) so add num i.e 4 to dict
Iteration 5 :=> num = 5 and dict has 1, 2, 3, 4
dict doesn't have 5 (because of s - num i.e 10 - 5) so add num i.e 5 to dict
Iteration 6 :=> num = 6 and dict has 1, 2, 3, 4, 5
dict have 4 (because of s - num i.e 10 - 6) so return [s - num, num] i.e [4, 6]
I think you might be overcomplicating things a little. There's no need to slice() or to push(), and there's no need to keep on looping after a result has been found:
function sumPairs(ints, s) {
for (let i = 0; i < ints.length; i++) {
for (let j = i; j < ints.length; j++) {
if (ints[i] + ints[j] == s) {
return [ints[i], ints[j]];
}
}
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
As #robby-cornelissen said there's no need to slice. And there's no need for push too as you can return the result simply.
When you do ints.slice(i) you get an array from that position.
You are comparing an int within an array in the second loop.
It didn't enter the second loop until "i === 5" which is in the ints array a [6]. Notice it didn't enter the second until you get an array of one element. Keep in mind 6 == [6] and 1<[6] and 2<[6] etc
Then it goes incrementing the value of j until you get the position of j that gets the value of ints which, summed by the value of the position i results on s.
const twoSum = (arr, target) => {
arr.sort((a, b) => a - b);
//double pointer -> increment, decrement accordingly
let leftPointer = 0;
let rightPointer = arr.length - 1;
while (leftPointer < rightPointer) {
if (arr[leftPointer] + arr[rightPointer] === target) {
return [arr[leftPointer], arr[rightPointer]];
}
if (arr[leftPointer] + arr[rightPointer] > target) {
rightPointer--;
}
if (arr[leftPointer] + arr[rightPointer] < target) {
leftPointer++;
}
}
};
console.log(twoSum([1, 2, 3, 4, 5, 6], 10));
I want to check whether an array has three odd integers consecutively (meaning their array positions, not necessarily in order numerically).
If there are then return true, else return false.
My code is:
var threeConsecutiveOdds = function(arr) {
for(var i = 0;i <arr.length;i++){
if(arr[i] % 2 !==0 && arr[i+1] % 2 !==0 && arr[i+2] % 2 !==0){
return true;
}else{
return false;
}
}
}
I want to ask why it is showing false for threeConsecutiveOdds([1, 2, 34, 3, 4, 5, 7, 23, 12])
Where it should return true as there is three consecutive odd integers in this array [5,7,23] are three consecutive odds.
Your code only ever checks the first 3 elements in the array.
Instead of immediately returning after checking 3 elements, you need to return only when you've checked the whole array.
To do this, put the return false after the end of your loop, so that it only returns that after it's checked all the possible elements.
N.B. you don't actually need to check the last 2 array elements because there aren't enough numbers after them for the sequence to be possible.
Demo, testing both true and false results:
var threeConsecutiveOdds = function(arr) {
for (var i = 0; i < arr.length-2; i++) {
if (arr[i] % 2 !== 0 && arr[i + 1] % 2 !== 0 && arr[i + 2] % 2 !== 0) {
return true;
}
}
return false;
}
console.log(threeConsecutiveOdds([1, 2, 34, 3, 4, 5, 7, 23, 12]));
console.log(threeConsecutiveOdds([1, 2, 34, 3, 5, 4, 7, 23, 12]));
Change to this:
for(var i = 0; i <arr.length-2; i++) {
if(arr[i] % 2 !==0 && arr[i+1] % 2 !==0 && arr[i+2] % 2 !==0){
return true;
}
}
return false;
There were two bugs. First, you were exiting as soon as you had checked the first three. The other one was reading past the end of the array, which is where -2 comes from.
There is no requirement of else statement, you can just write return false after for loop.
If three consecutive odd integers found, it will return true if not then it will complete the loop and then return the false flag.
var return_flag = function(array) {
for (var i = 0; i < array.length-2; i++) {
if (array[i] % 2 !== 0 && array[i + 1] % 2 !== 0 && array[i + 2] % 2 !== 0) {
return true;
}
}
return false;
}
console.info(return_flag([1, 2, 34, 3, 4, 5, 7, 23, 12]));
A little bit hacky but intuitive for checking three consecutive odds.
var threeConsecutiveOdds = (arr) => {
return arr.map((n) => n % 2).join``.includes('111');
};
console.log(threeConsecutiveOdds([1, 2, 34, 3, 4, 5, 7, 23, 12]));
If you want to have some fun, you could also implement a recursive solution:
const arr1 = [1, 2, 3, 2, 5, 9, 7, 11, 6, 6, 8, 4];
const arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const arr3 = ['foo', 7.5, 3, {}, 5, 13, 7, 8, 9, 10, 11];
const arr4 = [1,3];
function checkOddSequence(arr, sequenceLength, counter = 0) {
/*
* if the odd numbers counter is equal to the sequence
* length we want, return true
*/
if (counter === sequenceLength) return true;
/*
* if the array has less elements than the sequence
* length we want, return false
*/
if (arr.length < sequenceLength) return false;
if (typeof arr[0] !== 'number' || !Number.isInteger(arr[0]) || arr[0] % 2 === 0) {
/*
* if the first element of the array is not a number
* or is not an integer number or it is an even numbe,
* reset the odd numbers counter
*/
counter = 0;
} else {
// otherwise increment the odd numbers counter
counter++;
}
/*
* re-run the function, passing a copy of the array without the
* first element
* (passing a copy will prevent from modifying the original array)
*/
return checkOddSequence(arr.slice(1), sequenceLength, counter);
}
console.log('arr1:', arr1.join(","),'\nhas arr1 3 consecutive odd numbers?', checkOddSequence(arr1, 3));
console.log('arr2:', arr2.join(","),'\nhas arr2 3 consecutive odd numbers?', checkOddSequence(arr2, 3));
console.log('arr3:', arr3.join(","),'\nhas arr3 3 consecutive odd numbers?', checkOddSequence(arr3, 3));
console.log('arr4:', arr4.join(","),'\nhas arr4 3 consecutive odd numbers?', checkOddSequence(arr4, 3));
console.log('arr1:', arr1.join(","),'\nhas arr1 4 consecutive odd numbers?', checkOddSequence(arr1, 4));
console.log('arr1:', arr1.join(","),'\nhas arr1 5 consecutive odd numbers?', checkOddSequence(arr1, 5));
I thought I could use
$ [1,2,3,4,5].splice((this.length / 2), 1)[0]
but it gives me
$ 1
I tried
$ [1,2,3,4,5].splice(function() { return this[this.length / 2, 1]})
but it gives me
[ 1, 2, 3, 4, 5 ]
I'm looking for a solution that gives me an integer and for even arrays is the lower of the two, e.g.
[1,2,3,4] givees 2
[1,2,3,4,5] gives 3
[1,2,3,4,5,6] gives 3
[1,2,3,4,5,6,7] gives 4
The issue is with this reference. Try this:
console.log(getMiddle([1,2,3,4]));
console.log(getMiddle([1,2,3,4,5]));
console.log(getMiddle([1,2,3,4,5,6]));
console.log(getMiddle([1,2,3,4,5,6,7]));
function getMiddle(arr){
return arr.splice(Math.floor((arr.length-1) / 2), 1)[0]
}
However, As #jonrsharpe 's comment states, splicing a single-element array from an index to the same index plus one then getting the first value in the result creates a redundant array. A better way to get the middle element would be the following:
console.log(getMiddle([1,2,3,4]));
console.log(getMiddle([1,2,3,4,5]));
console.log(getMiddle([1,2,3,4,5,6]));
console.log(getMiddle([1,2,3,4,5,6,7]));
function getMiddle(arr){
return arr[Math.floor((arr.length - 1) / 2)];
}
You should use something like that.
var data, remaining, hold, result;
data = ["1","2","3","4","5","6","7","8", "9"];
remaining = data.length % 2;
hold = Math.floor(data.length / 2);
result = data[(remaining + hold - 1)];
document.write(result);
You could create a prototype for getting the middle element/s.
Array.prototype.middle = function () {
const
half = this.length >> 1,
offset = 1 - this.length % 2;
return this.slice(half - offset, half + 1);
};
console.log([1, 2, 3, 4, 5].middle()); // [3]
console.log([1, 2, 3, 4, 5, 6].middle()); // [3, 4]
console.log([1, 2, 3, 4].middle()); // [2, 3]
.as-console-wrapper { max-height: 100% !important; top: 0; }
You cannot use this as a parameter because this is supposed to be called inside functions, whereas splice accept as parameters integers. If you really want to use this you may use a prototype. Use Math.floor function since arrays indexes only accept integers, and Math.floor rounds up to the lowest integer (ex: Math.floor(2.5) === 2).
Array.prototype.getMiddle = function () {
return this[Math.floor(this.length/2)]
}
console.log([1,2,3,4,5].getMiddle()) // 3
The above function only works when the length of the array is an odd number, since arrays whose length is an even number do not have "middle" element.
If you want to check if the array has a middle
Array.prototype.getMiddle = function () {
return (this.length % 2) ? this[Math.floor(this.length/2)] : null
}
console.log([1,2,3,4,5].getMiddle()) // 3
console.log([1,2,4,5].getMiddle()) // null
Alternative solutions:
var arr = [1,2,3,4,5]
var middleEl = arr[Math.floor(arr.length/2)]
console.log(middleEl) // 3
If you want to use splice
var arr = [1,2,3,4,5]
var middleEl = arr.splice((arr.length / 2), 1)[0]
console.log(middleEl)
If you want a function
console.log(middleEl([1,2,3,4,5])) //3
console.log(middleEl([1,2,4,5])) //null
function middleEl (arr) {
return (arr.length % 2) ? arr[Math.floor(arr.length/2)] : null
}
let arr = [ 1, 2, 3, 4, 5 ]
let len = arr.length;
let mid = Math.floor(len / 2);
console.log(arr[mid]);
// or
console.log(arr.slice(mid, mid + 1));
or if you want the middle two, you can do mid + 2 using a var that tests to see if the length is even.
Why not simply, assuming a.length > 0:
const a = [1, 2, 3, 4, 5]
console.log(a[(a.length - 1) >> 1])
const b = [1, 2, 3, 4, 5, 6]
console.log(b[(b.length - 1) >> 1])
I think this should be a fairly fast way of doing it. The >> operator is an integer shift, which divides the number by two - ignoring decimals.
I want to write a function with a while-statement that determines the length of the largest consecutive subarray in an array of positive integers. (There is at least one consecutive array.) For instance:
Input: [6, 7, 8, 6, 12, 1, 2, 3, 4] --> [1,2,3,4]
Output: 4
Input: [5, 6, 1, 8, 9, 7] --> [1,8,9]
Output: 3
Normally I would try to use for-loops and the array.push method later on, however, to get more practice I wanted to use a while-loop and another 'array-lengthening' method, not sure how it's called, see below.
My try:
function longestSub (input) {
let i=0;
let idx=0;
let counterArr=[1]; //init. to 1 because input [4,5,3] equals sub-length 2
while(i<input.length) {
if (input[i]+1 > input[i]) {
counterArr[0+idx] += 1
}
else {
i=input.indexOf(input[i]); //should start loop at this i-value again
idx +=1;
counterArr[0+idx] = 1; //should init new array index
}
i++
}
return Math.max(...counterArr)
}
My idea was that the else-statement would reset the if-statement when it fails and start again from the position it failed at with updated variables. It would also initialize another array index with value 1 that gets subsequently updated afterwards with the if-statement.
Finally I have a counterArr like [1,2,3] where 3 stands for the largest consecutive subarray. Thanks everyone reading this or helping a beginner like me to get a deeper understanding of Javascript.
Here is a simple solution using while loop:
let arr =[6, 7, 8, 6, 12, 1, 2, 3, 4]
let endIndx = 0, maxLength = 0, indx = 1,tempMax = 0;
while (indx < arr.length) {
if (arr[indx] > arr[indx - 1])
tempMax++;
else {
if (maxLength <= tempMax) {
maxLength = tempMax+1
endIndx = indx
tempMax=0;
}
}
++indx
}
if (maxLength < tempMax) {
maxLength = tempMax
endIndx = indx
}
console.log("Sub array of consecutive numbers: ", arr.slice(endIndx-maxLength,endIndx))
console.log("Output :",maxLength)
You could take an approach which just counts the length and checks with the max found length if the continuous items.
function longestSub(input) {
let i = 1, // omit first element and use later element before this index
max = 0,
tempLength = 1; // initialize with one
if (!input.length) return 0;
while (i < input.length) {
if (input[i - 1] < input[i]) {
tempLength++;
} else {
if (max < tempLength) max = tempLength;
tempLength = 1;
}
i++;
}
if (max < tempLength) max = tempLength;
return max;
}
console.log(longestSub([])); // 0
console.log(longestSub([6, 7, 8, 6, 12])); // 3
console.log(longestSub([5, 6, 1, 2, 8, 9, 7])); // 4
console.log(longestSub([6, 7, 8, 6, 12, 1, 2, 3, 4, 5])); // 5
Unless this really is a learning exercise, I'd rather focus on the approach than on the implementation.
Create a function that slices an array of numbers into arrays of consecutive numbers:
The first two conditions deal with the simplest cases:
If input is empty, output is empty [] -> []
If input is exactly one element, the output is known already [42] -> [[42]]
Then comes the "meat" of it. The output is an array of array. Let's start by creating the first sub array with the first element of the initial array. Let's use [6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5] as the input.
Start with [[6]] then iterate over [7, 8, 6, 12, 1 ,2 ,3, 4, 5]. Here are the result at each iteration:
7 > 6 true -> [[6,7]]
8 > 7 true -> [[6,7,8]]
6 > 8 false -> [[6],[6,7,8]]
12 > 6 true -> [[6,12],[6,7,8]]
1 > 12 false -> [[1],[6,12],[6,7,8]]
2 > 1 true -> [[1,2],[6,12],[6,7,8]]
3 > 2 true -> [[1,2,3],[6,12],[6,7,8]]
4 > 3 true -> [[1,2,3,4],[6,12],[6,7,8]]
5 > 4 true -> [[1,2,3,4,5],[6,12],[6,7,8]]
const slices =
xs =>
xs.length === 0 ? []
: xs.length === 1 ? [[xs[0]]]
: xs.slice(1).reduce
( ([h, ...t], x) =>
x >= h[h.length - 1]
? [h.concat(x), ...t]
: [[x], h, ...t]
, [[xs[0]]]
);
slices([6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5]);
//=> [ [1, 2, 3, 4, 5]
//=> , [6, 12]
//=> , [6, 7, 8]
//=> ]
Then you create a function that takes an array of slices and return the biggest one:
const max_slices =
xs =>
xs.reduce
( (a, b) =>
a.length > b.length
? a
: b
);
max_slices(slices([6, 7, 8, 6, 12, 1 ,2 ,3, 4, 5]));
//=> [1, 2, 3, 4, 5]
I’m trying to generate all valid combinations of numbers from an array of digits. Let’s assume we have the following:
let arr = [1, 2, 9, 4, 7];
We need to output something like this:
1 2 9 4 7
1 2 9 47
1 2 94 7
1 2 947
1 29 4 7
1 29 47
1 294 7
1 2947
12 9 4 7
12 9 47
12 94 7
12 947
129 4 7
129 47
1294 7
12947
An invalid number would be 91, 497, 72 and so on.
I tried this but I’m not satisfied with the result:
const combination = (arr) => {
let i, j, temp;
let result = [];
let arrLen = arr.length;
let power = Math.pow;
let combinations = power(2, arrLen);
for (i = 0; i < combinations; i += 1) {
temp = '';
for (j = 0; j < arrLen; j++) {
if ((i & power(2, j))) {
temp += arr[j];
}
}
result.push(temp);
}
return result;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Any ideas?
This code does what you want:
const arr = [1, 2, 9, 4, 7],
result = Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))
.map((binary) => JSON.parse("[" + arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("") + "]"));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It results in:
[
[12947],
[1294, 7],
[129, 47],
[129, 4, 7],
[12, 947],
[12, 94, 7],
[12, 9, 47],
[12, 9, 4, 7],
[1, 2947],
[1, 294, 7],
[1, 29, 47],
[1, 29, 4, 7],
[1, 2, 947],
[1, 2, 94, 7],
[1, 2, 9, 47],
[1, 2, 9, 4, 7]
]
Assuming, the expected result does not depend on order, the spaces represent a binary pattern:
12947 => 0000
1294 7 => 0001
129 47 => 0010
…
1 29 47 => 1010
…
1 2 9 4 7 => 1111
We can utilize this pattern with a counter that we convert to a binary string. We also pad that string with 0 so it always remains 4 digits long:
index.toString(2).padStart(arr.length - 1, "0")
For n digits in arr, there are exactly 2n - 1 combinations, so we use:
{length: 2 ** (arr.length - 1)}
This is an object that has a length property of 2arr.length - 1.
We combine both those things into an Array.from call which accepts two arguments:
an object to turn into an array
a function for mapping each slot
Turning an object with a length property into an array means that we create an array with length many slots.
The mapping function accepts the index of a slot as the second parameter. We only use the index — as a counter for our binary number.
So, finally this whole expression:
Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))
evaluates to the following array:
[
"0000",
"0001",
"0010",
"0011",
"0100",
"0101",
"0110",
"0111",
"1000",
"1001",
"1010",
"1011",
"1100",
"1101",
"1110",
"1111"
]
We need to further map this to the final result:
.map((binary) => …)
For each array element, binary is one of the binary strings from the array above.
In order to turn e.g. "0110" into something like "12,9,47", we need to map over arr as well. Every digit num from arr should be followed by , at position, iff binary is 1 at position:
arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("")
The expression (Number(binary[position]) ? "," : "") evaluates binary at the specified position as a number. If it’s truthy, i.e. anything but 0, it evaluates to ",", if it’s falsy, i.e. 0, it evaluates to "".
So an intermediate array would look like ["1", "2,", "9,", "4", "7"]. All of this is joined together to "12,9,47".
Then, with JSON.parse("[" + … + "]") it’s being treated and parsed as an array, so it turns into [12, 9, 47]. Since these steps are applied for each binary string, you’ll end up with the final result.
2 ** (arr.length - 1) can be replaced by Math.pow(2, arr.length - 1) if ECMAScript 7 is not supported.
{length: 2 ** (arr.length - 1)} can be replaced by new Array(2 ** (arr.length - 1)).
(Number(binary[position]) ? "," : "") can be replaced by ["", ","][Number(binary[position])]. In this case the evaluated number will be used as an index for a temporary array.
So you need to iterate over all the combinations of "space" and "not space" between all the numbers. With n items, there will be n - 1 spaces, and 2 ** (n - 1) different lists.
So you could do something like this to get all the possible lists:
const combination = arr => {
const len = arr.length;
const n = Math.pow(2, len - 1);
const combinations = [];
for (let i = 0; i < n; i++) {
let this_combination = [arr[0]];
for (let j = 1; j < len; j++) {
if (i & Math.pow(2, j - 1)) {
// If the jth bit is on, no space. Append to the last element.
const last_index = this_combination.length - 1;
this_combination[last_index] = +(this_combination[last_index] + '' + arr[j]);
} else {
// Otherwise create a new list item.
this_combination.push(arr[j]);
}
}
// Consider making this function a generator and making this a yield.
combinations.push(this_combination);
}
return combinations;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result.map(line => line.join(' ')).join('\n'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you wanted each individual item seperately, for each item in the array, combine it with no other item, then just the next item, then the next 2 items, etc. untill the end:
const combination = arr => {
const len = arr.length;
const combinations = [];
for (let i = 0; i < len; i++) {
let item = arr[i];
combinations.push(item);
for (let j = i + 1; j < len; j++) {
item = +(item + '' + arr[j]);
combinations.push(item);
}
}
return combinations;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result.join('\n'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take a recursive approach by iterating the array and insert a space or not and fork the calling of the same function with an incremented index.
function combine(array) {
function fork(i, p) {
if (i === array.length) {
result.push(p);
return;
}
fork(i + 1, p + ' ' + array[i]);
fork(i + 1, p + array[i]);
}
var result = [];
fork(1, array[0].toString());
return result;
}
console.log(combine([1, 2, 9, 4, 7]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could do this by using below code where 3 pointer is used,
1st pointer print 0th position to cursor position.
2nd pointer print cursor to diffidence position in each iteration .
3rd pointer print cursor position to last position.
let arr = [1, 2, 9, 4, 7];
console.log(arr.join(','));
for(let diff=2;diff<=arr.length;diff++){
for(i=0,j=diff;arr.length>=i+diff;j++,i++){
var temp = [];
if(i>0)
temp.push(arr.slice(0,i).join(','));
temp.push(arr.slice(i,j).join(''));
if(j<arr.length)
temp.push(arr.slice(j,arr.length).join(','));
console.log(temp.join(','));
}
}