HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

JavaScript program to find if array is in Arithmetic or Geometric sequence

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
javascriptarrayprogramsequencefindgeometricarithmetic

Problem

Given an array of numbers I've to write a function to return the string "Arithmetic" if the sequence follows an arithmetic pattern or return "Geometric" if it follows a geometric pattern. If the sequence doesn't follow either pattern return "neither arithmetic and geometric".

I'm a beginner and I thought of following solution first. How do I improve on it and write better code next time?

var arr =[2,4,6,8,10];// [2,6,18,54]- Geometric
var arthCount=0;
var geoCount=0;
    function ArthGeo(){
        for (var i=0;i<arr.length-2;i++){
             if(arr[i+1]-arr[i]===arr[i+2]-arr[i+1]){
                 arthCount++;
            }
            else if(arr[i+1]/arr[i] ===arr[i+2]/arr[i+1]){
                 geoCount++;
            }
            else return "neither arithmetic nor geometric";
        }
         if(arthCount===arr.length-2)
             return "Arthematic series";
         else if(geocount===arr.length-2)
             return "Geometric series";
     }    
 console.log(ArthGeo());

Solution

This is great example to practice identifying the right abstraction.

In testing to see if an array is geometric or arithmetic series, what you are really doing is testing if a particular mathemtical relation holds for each element. That is, the heart of your program is in these 2 lines:

if(arr[i+1]-arr[i]===arr[i+2]-arr[i+1]){
//...
else if(arr[i+1]/arr[i] ===arr[i+2]/arr[i+1]){


Let's go ahead and extract just these relations into their own functions:

// This tells if an arithmetic relation holds at a particular index of the array
// The function signature here is chosen to work with javascript's every method
// The reason will become clear below.
function isArithmeticAtIndex(elm, i, arr) {
  if (i < 2) return true; // trivially true when it can't be false
  return arr[i] - arr[i-1] === arr[i-1] - arr[i-2];
}

function isGeometricAtIndex(elm, i, arr) {
  if (i < 2) return true;
  if (arr[i-1] == 0 || arr[i-2] == 0) return false; // can't divide by 0
  return arr[i] / arr[i-1] === arr[i-1] / arr[i-2];
}


Now we'll create a generic function that tells us if a particular mathematical relation holds at every elment of an array:

function hasSeriesRelation(arr, relationFn) {
  // geometric and arithmetic series (and most others) 
  // don't make sense with less than 3 elements
  if (arr.length < 3) return false;
  return arr.every(relationFn);
}


At this point, we are basically done. We can use what we've written as follows:

a = [1,2,3,4];
hasSeriesRelation(a, isArithmeticAtIndex);
// => true
a = [1,2,3,5];
hasSeriesRelation(a, isArithmeticAtIndex);
// => false
a = [1,2,4,8];
hasSeriesRelation(a, isGeometricAtIndex);
// => true
a = [1,2,4,9];
hasSeriesRelation(a, isGeometricAtIndex);
// => false


But writing hasSeriesRelation(a, isGeometricAtIndex) is cumbersome, so let's wrap these up in their own functions, and make them array methods:

Array.prototype.isArithmeticSeries = function() { return hasSeriesRelation(this, isArithmeticAtIndex) };
Array.prototype.isGeometricSeries = function() { return hasSeriesRelation(this, isGeometricAtIndex) };


And now we can write things like:

[1,2,4,8].isGeometricSeries();
[1,2,3,4].isArithmeticSeries();


Side Note: Some consider extending Array.prototype bad practice. I think it can be okay depending on your circumstances. See this post for more discussion. In any case, it's only marginally relevant to this discussion, because you can easily rewrite the above to functions with signatures like function isArithmeticSeries(arr)

Finally, note that we have gained the ability to quickly and easily add new types of series. For example, we might want to identify Fibonacci-like series:

function isFibonacciAtIndex(elm, i, arr) {
  if (i  true

Code Snippets

if(arr[i+1]-arr[i]===arr[i+2]-arr[i+1]){
//...
else if(arr[i+1]/arr[i] ===arr[i+2]/arr[i+1]){
// This tells if an arithmetic relation holds at a particular index of the array
// The function signature here is chosen to work with javascript's every method
// The reason will become clear below.
function isArithmeticAtIndex(elm, i, arr) {
  if (i < 2) return true; // trivially true when it can't be false
  return arr[i] - arr[i-1] === arr[i-1] - arr[i-2];
}

function isGeometricAtIndex(elm, i, arr) {
  if (i < 2) return true;
  if (arr[i-1] == 0 || arr[i-2] == 0) return false; // can't divide by 0
  return arr[i] / arr[i-1] === arr[i-1] / arr[i-2];
}
function hasSeriesRelation(arr, relationFn) {
  // geometric and arithmetic series (and most others) 
  // don't make sense with less than 3 elements
  if (arr.length < 3) return false;
  return arr.every(relationFn);
}
a = [1,2,3,4];
hasSeriesRelation(a, isArithmeticAtIndex);
// => true
a = [1,2,3,5];
hasSeriesRelation(a, isArithmeticAtIndex);
// => false
a = [1,2,4,8];
hasSeriesRelation(a, isGeometricAtIndex);
// => true
a = [1,2,4,9];
hasSeriesRelation(a, isGeometricAtIndex);
// => false
Array.prototype.isArithmeticSeries = function() { return hasSeriesRelation(this, isArithmeticAtIndex) };
Array.prototype.isGeometricSeries = function() { return hasSeriesRelation(this, isGeometricAtIndex) };

Context

StackExchange Code Review Q#107074, answer score: 3

Revisions (0)

No revisions yet.