I'm currently working on an array function that converts subarrays of consecutive numbers into strings denoting that range of numbers — for example, this array...
[1, 2, 3, 6, 8, 10, 11, 12, 15, 18]
...would become this array:
["1-3", 6, 8, "10-12", 15, 18]
I've been able to develop a function that mostly works, but I've encountered a weird error where all the elements past the final range of numbers spliced into the array are completely deleted. For example, the test array above actually becomes this:
["1-3", 6, 8, "10-12"]
This is the code I've written so far. It's not super pretty yet, but as I mentioned above, it gets the job done right up until the very end:
let testArray = [1, 2, 3, 6, 8, 10, 11, 12, 15, 18];
for (i = 0; i < testArray.length; i++) {
let consecutives = [];
consecutives.push(testArray[i]);
let j = i + 1;
while (j < testArray.length) {
if (testArray[j] == (testArray[j - 1] + 1)) {
consecutives.push(testArray[j]);
j++;
} else {
break;
}
}
if (consecutives.length > 2) {
let range = String(testArray[i]) + "-" + String(testArray[j - 1]);
console.log(testArray);
console.log(testArray[i]);
console.log(testArray[j]);
testArray.splice(i, j, range);
}
}
console.log(testArray);
These are the console logs output by that code:
Array(10) [ 1, 2, 3, 6, 8, 10, 11, 12, 15, 18 ]
1
6
Array(8) [ "1-3", 6, 8, 10, 11, 12, 15, 18 ]
10
15
Array(4) [ "1-3", 6, 8, "10-12" ]
I initially figured this was caused by a mix-up with array indexes, but playing around with the index-1s hasn't fixed the problem yet. Has anyone else ever had a similar issue with JavaScript's splicing, and if so, how were you able to get it working?
The problem lies in one line of code:
testArray.splice(i, j, range);
According to the MDN, the second argument specifies how many elements in the array to delete.
deleteCount
An integer indicating the number of elements in the array to remove from start.
However, the code defines this argument as the index of the last array to remove from:
let j = i + 1;
The solution is to get the difference between i and j before passing it to splice:
testArray.splice(i, j - i, range);
When you do:
testArray.splice(i, j, range);
You are forgetting that j is the right limit index of the array that you want to erase, so you need to subtract i that is the left limit:
testArray.splice(i, j - i, range);
let testArray = [1, 2, 3, 6, 8, 10, 11, 12, 15, 18];
for (i = 0; i < testArray.length; i++) {
let consecutives = [];
consecutives.push(testArray[i]);
let j = i + 1;
while (j < testArray.length) {
if (testArray[j] == (testArray[j - 1] + 1)) {
consecutives.push(testArray[j]);
j++;
} else {
break;
}
}
if (consecutives.length > 2) { // doesn´t it should be > 1 ??
let range = String(testArray[i]) + "-" + String(testArray[j - 1]);
console.log(testArray);
console.log(testArray[i]);
console.log(testArray[j]);
testArray.splice(i, j - i, range);
}
}
console.log(testArray);
Related
I am new to Javascript and at the moment I'm learning how "arrays" are used.
In my code below I have 12 numbers held by an array variable. Next, the for loop is iterating over the indexes to check which values have 2 or more digits, the while-loop then summarizes the digits (e.g. value '130' at index 8, will be 1+3+0=4).
Final step..and also where I'm stuck:
I need to sum up all the "new" index values and return the result in a variable.
With the numbers provided in the code, the result would be '50'.
Anyone have clue on how to do this? I've tried the conventional for-loop with sum += array[i], but it doesn't work.
var arrChars = [4, 2, 14, 9, 0, 8, 2, 4, 130, 65, 0, 1];
for (var i = 0; i < arrChars.length; i++) {
var digsum = 0;
while (arrChars[i] > 0) {
digsum += arrChars[i] % 10;
arrChars[i] = Math.floor(arrChars[i] / 10);
}
var sum = 0; // this last part won't work and I just get "nan", 12 times
for (var j = 0; j < arrChars.length; j++) {
sum += parseInt(digsum[j]);
}
console.log(sum); // desired output should be '50'
}
Move digsum outside and it will contain the sum of every number in it:
var arrChars = [4, 2, 14, 9, 0, 8, 2, 4, 130, 65, 0, 1];
var digsum = 0;
for (var i = 0; i < arrChars.length; i++) {
while (arrChars[i] > 0) {
digsum += arrChars[i] % 10;
arrChars[i] = Math.floor(arrChars[i] / 10);
}
}
console.log(digsum); // desired output should be '50'
I'd make this easy and just flatten the array of numbers into a string of digits, split that into an array of single digits, and add them together:
var arrChars = [4, 2, 14, 9, 0, 8, 2, 4, 130, 65, 0, 1];
console.log([...arrChars.join('')].reduce((agg, cur) => agg += +cur, 0));
I have an array with some numbers like the following:
[1, 2, 3, 4, 6, 7, 8, 10, 15, 16, 17]
I'd like to show all numbers that are direct after each other (n+1) in one line and if there is a gap, this should be separated. This will either be done in javascript/jquery.
The user would see it like this:
1 - 4, 6 - 8, 10, 15 - 17
I'm guessing the only solution to this would be to loop through the array and see if the next number is n+1 and if it is, lump it together, else start on a new series?
I think I know how I would do it that way but interested to know if there is some other way to do it either in javascript/jquery?
You can loop once while keeping track of the current starting number.
let arr = [1, 2, 3, 4, 6, 7, 8, 10, 15, 16, 17];
let start = arr[0],
res = [];
for (let i = 1; i < arr.length; i++) {
if (arr[i + 1] - arr[i] != 1 || i == arr.length - 1) {
res.push(start + " - " + arr[i]);
start = arr[i + 1];
}
}
console.log(res);
I am writing an algorithm for finding two elements in an array that sums up to the provided value. i.e for array [2, 7, 5, 3, 4, 11, 12, 56] and value 9 I am finding two elements for eg. 2 and 7 which adds to our provided value 9. I am getting the final result as [ [ 2, 7 ], [ 4, 5 ] ]. Please find the code below
const getSumOfValuesInArr = (arr, val) => {
var result = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i; j < arr.length; j++) {
if (arr[j] + arr[i] === val) {
result.push([arr[i], arr[j]]);
}
}
}
console.log(result);
return result;
};
getSumOfValuesInArr([2, 7, 5, 3, 4, 11, 12, 56], 9);
But as you can it is a bit expensive. How can I write a better algorithm for better performance? Please help.
You could take a single loop and store seen values in a hash table.
Then check if the delta of the wanted sum and the actual value is seen before then add the pair to the result set.
const getSumOfValuesInArr = (arr, val) => {
var result = [],
seen = {};
for (let i = 0; i < arr.length; i++) {
if (seen[val - arr[i]]) result.push([val - arr[i], arr[i]]);
seen[arr[i]] = true;
}
return result;
};
console.log(getSumOfValuesInArr([2, 7, 5, 3, 4, 11, 12, 56], 9));
I have an array like this:
arrayA = [1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2];
I need to get separated numbers in groups like this:
arrayB = [1234,5678,9123,4567,8912];
As you can see its the same arrayA but in groups of 4 values that are now new numbers.
I was able to make it work with a bug like this: arrayB=[undefined1234,undefined5678];
with this code:
for (var i = 0; i < 20; i++) {
if (i/4== n+1){
arrayB[n] = temp;
n++;
}
temp += arrayA[i];
}
And thats it. I understand the bug, it is because of that += but am not sure how to do this any other way.
this code will do that trick
var arrayA = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2,3,4];
var arrayB = [];
for (var x = 0; x < arrayA.length; x += 4) {
arrayB.push(arrayA.slice(x, x + 4).join(''));
}
console.log(arrayB);
Update
Millie has raised a fair point. if you need numbers in the result array, use following statement in for loop
arrayB.push(parseInt(arrayA.slice(x, x + 4).join('')));
Try setting temp to "" both before the loop starts and after each time you assign to arrayB (and when you make that assignment, turn the string in step into an integer). And you may need to make a final assignment to arrayB after the for loop finishes.
I would do it like this:
arrayA = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2];
temp = arrayA.join('');
count = 4;
grouped = [];
max = temp.length / count;
for (i = 0; i < max; i++) {
grouped.push(parseInt(temp.substr(i * 4, 4)));
}
console.log(grouped);
Little numbers to strings conversion, and returning of numbers. :)
Demo: http://jsfiddle.net/hue0a1wb/
If I have an array of [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7] and wanted to find each case of 3 consecutive numbers (whether ascending or descending), how would I do that?
Second part would be then to alert an array with the index of each of these sequences.
For ex. the previous array would return [0,4,6,7].
So far I have this... which is a rough start
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 1; i < arr.length; i++) {
if ((arr[i] - arr[i-1] != 1) && (arr[i] - arr[i+1] != 1)) {
results.push(arr[i]);
}
}
alert(results);
Thanks for the help!
Thanks for the math.abs pointer. This is what I ended up doing:
var array = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var indexes = [];
for(var i=0; i < array.length; i++) {
var diff = array[i+1] - array[i];
if(Math.abs(diff)==1 && array[i+1]+diff == array[i+2]) {
indexes.push(i);
}
}
alert(indexes);
It'd be interesting to know the context of this task as well... Anyway, here's my solution:
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
var limit = arr.length - 1;
var sequence = 0;
for (var i = 0; i < limit; ++i) {
var diff = arr[i+1] - arr[i];
if (sequence && sequence === diff) {
results.push(i-1);
continue;
}
sequence = (diff === 1 || diff === -1) // or ... Math.abs(diff) === 1
? diff
: 0;
}
console.log(results);
The idea is simple: we don't need to compare two neighbors twice. ) It's enough to raise a kind of sequence flag if this comparation starts a sequence, and lower it if no sequence is there.
This is a very literal approach to your question - I have only checked forwards numbers, but adding reverse would be done almost in the same way
var arr = [1, 2, 3, 4, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 0; i < arr.length; i++) {
// if next element is one more, and one after is two more
if (arr[i+1] == arr[i]+1 && arr[i+2] == arr[i]+2){
// store the index of matches
results.push(i);
// loop through next numbers, to prevent repeating longer sequences
while(arr[i]+1 == arr[i+1])
i++;
}
}
console.log(results);
You need to look closely at your expression in your if statement.
It currently says:
If the difference between the current element and previous element is not 1, and
If the difference between the current element and next element is not 1
then it's a result.
So, on the face of it, that's an incorrect logical statement to determine if the current element is in the middle of a consecutive set of three.
In addition, this doesn't account for an ascending or descending set of three either.
Try figuring out, in words, what the condition would look like and go from there.
Some things to consider
I suggest you start going through the list from i = 2
Research Math.abs
This is I think a simpler way to do it. First check the average of the left and right number is equal to the middle, then check that the absolute value of either neighbor is one.
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var indexes = [];
for(var i=1; i < arr.length; i++) {
if((arr[i-1]+arr[i+1]) / 2 == arr[i] && Math.abs(arr[i]-arr[i-1]) == 1) {
indexes.push(i-1);
}
}
alert(indexes);
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 0; i < arr.length - 2; i++) {
if ((arr[i+1] - arr[i] === 1) && (arr[i+2] - arr[i+1] === 1)) {
results.push({
i:i,
mode:'up',
arr:[arr[i],arr[i+1],arr[i+2]
});
}
if ((arr[i+1] - arr[i] === -1) && (arr[i+2] - arr[i+1] === -1)) {
results.push({
i:i,
mode:'down',
arr:[arr[i],arr[i+1],arr[i+2]
});
}
}
alert(results);