最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - determine if array is arithmetic or geometric progression (from Coderbyte) - Stack Overflow

programmeradmin0浏览0评论

Here is my functional code, as far as coderbyte is concerned. But I have a feeling it shouldn't be this complicated. Am I missing a simple trick?

function ArithGeo(arr)
{
    var array_type = -1;
    if (arr.length <= 2) return true;

    var a = arr[1], r = a/arr[0], i;
    for (i = 2; i < arr.length; ++i) {
        if ((a *= r) == arr[i]){
            array_type = "Geometric";
        }
        else{
            array_type = -1;
            break;
        }
    }

    if (array_type == "Geometric")
        return array_type;


    a = arr[1], d = a - arr[0], i;
    for (i = 2; i < arr.length; ++i) {
        if ((a += d) == arr[i]){
            array_type = "Arithmetic";
        }
        else {
            array_type = -1;
            break;
        }
    }
    return array_type;
}

ArithGeo([3,9,15,21,27, 28]);

Here is my functional code, as far as coderbyte is concerned. But I have a feeling it shouldn't be this complicated. Am I missing a simple trick?

function ArithGeo(arr)
{
    var array_type = -1;
    if (arr.length <= 2) return true;

    var a = arr[1], r = a/arr[0], i;
    for (i = 2; i < arr.length; ++i) {
        if ((a *= r) == arr[i]){
            array_type = "Geometric";
        }
        else{
            array_type = -1;
            break;
        }
    }

    if (array_type == "Geometric")
        return array_type;


    a = arr[1], d = a - arr[0], i;
    for (i = 2; i < arr.length; ++i) {
        if ((a += d) == arr[i]){
            array_type = "Arithmetic";
        }
        else {
            array_type = -1;
            break;
        }
    }
    return array_type;
}

ArithGeo([3,9,15,21,27, 28]);
Share Improve this question edited Aug 17, 2013 at 5:03 dwilbank asked Aug 17, 2013 at 4:48 dwilbankdwilbank 2,5202 gold badges28 silver badges41 bronze badges
Add a comment  | 

6 Answers 6

Reset to default 7
function ArithGeo(arr) { 

var diff = arr[1] - arr[0];
var ratio = arr[1] / arr[0];

var arith = true;
var geo = true;

for(var i = 0; i < arr.length - 1; i++)
{
    if( arr[i + 1] - arr[i] !== diff )
      arith = false;
    if(arr[i + 1] / ratio !== arr[i])
      geo = false;
}

if(arith === true)
    return "arithmetic";
else if(geo === true)
    return" geometric";
else
    return -1;

}

Here's a simple solution as well. I'm either looking for a geometric pattern, where a given element will be divisible by the previous element, or an arithmetic pattern, where each element increases by a constant amount. Two variables, diff and ratio, contain each pattern to search for throughout the array.

I start by assuming that arith and geo are true, and if I find an example where one is not true, I set its value to false. Note that your code has two for loops, with the exact same conditions. This is a good indication that your code can be condensed into one loop.

With each pass through the loop, I test whether the conditions are present to set either arith or geo to false. Finally, after the loop exits, I will determine if either arith or geo remained true throughout the loop. If not, I return - 1 as the problem from Coderbyte requests.

edit: quick note on my for loop condition. Since I am checking the value of i + 1 with each pass, I make sure that I don't reach out of bounds by setting my exit condition to arr.length - 1. This way, i + 1 can still reach the last element, and will be sure not to overreach.

For arithmetic progression, subtract each element from previous element; their difference should be equal; for geometric, divide each element by the previous element, the ratio should stay the same. As for divide by zero when you meet 0, javascript gives you Inf (and it certainly is not a geometric progression). Because floats are inaccurate, maybe you'd want to store the min and max of these values and then see if they are close enough to each other.

function arithGeo(arr) {
    var minRatio = 1/0,
        maxRatio = -1/0,
        minDiff  = 1/0,
        maxDiff  = -1/0,
        epsilon  = 0.000001,
        i,
        ratio,
        diff;

    if (arr.length <= 2) {
        return;
    }

    for (i = 1; i < arr.length; ++i) {
        diff  = arr[i] - arr[i - 1];
        ratio = arr[i] / arr[i - 1];
        minDiff  = Math.min(diff, minDiff);
        maxDiff  = Math.max(diff, maxDiff);
        minRatio = Math.min(ratio, minRatio);
        maxRatio = Math.max(ratio, maxRatio);
    }

    if (Math.abs(minDiff - maxDiff) < epsilon) {
        return "Arithmetic";
    }

    if (Math.abs(minRatio - maxRatio) < epsilon) {
        return "Geometric";
    }

    return;
}

alert(arithGeo([3,9,15,21,27,28]));
alert(arithGeo([3,9,15,21,27]));
alert(arithGeo([4,2,1,0.5]));

It might not be the most efficient way to solve the problem, and it doesn't address the epsilon Problem, that Antti Haapala mentioned, but this is my solution to the problem:

function sequenceMatches(arr, fn) {
  var compare = fn(arr[0], arr[1]);
  for (var i = 2; i < arr.length; i++) {
    if (fn(arr[i - 1], arr[i]) !== compare) return false;
  }
  return true;
}
function ArithGeo(arr) { 
  if (sequenceMatches(arr, function(a, b) { return b - a; })) return 'Arithemetic';
  if (sequenceMatches(arr, function(a, b) { return b / a; })) return 'Geometric';
  return -1;        
}

I choose to solve that in two different functions, as that helps to clean up the code imho.

function ArithGeo(arr) { 
var apCnt = 1;
 var gpCnt = 1;
  var diff = arr[1] - arr[0]; //ap difference
  var div = arr[1]/arr[0];   //gp difference
  for(var i=1;i<arr.length-1;i++){ //traverse array
    if(arr[i+1] - arr[i] == diff) { //check for ap
      apCnt+=1;
    }
    else if(arr[i+1]/arr[i] == div) { //check for gp
      gpCnt+=1;
    }
    else{
      break;  //break if not ap or gp
    }
  }

  return apCnt == arr.length-1 ? "Arithmetic": gpCnt == arr.length-1 ? "Geometric": -1;  //return if its ap or gp

}
function ArithGeo(arr){
    if(arr == null || !Array.isArray(arr)){
        return "error";
    }

    var length = arr.length;
    if(length === 0){
        return "neither";
    }
    if(length === 1){
        return "both";
    }

    var arithCount = 0,
        geoCount = 0,
        d = arr[1] - arr[0],
        q = arr[1] / arr[0];
    for(var i = length - 1; i > 0; i--){
        if((arr[i] - arr[i-1]) === d){
            arithCount++;
        }
        if((arr[i] / arr[i-1]) === q){
            geoCount++;
        }
    }

    if(arithCount === length - 1){
        return "Arithmetic";
    }else if (geoCount === length - 1){
        return "Geometric";
    }else if((arithCount === length - 1) && (geoCount === length - 1)){
        return "both";
    }else{
        return "neither";
    }
}

Sorry, only considered the integer sequence. @Antti Haapala's answer is correct.

Extremely late but I pretty much did the same on my own (novice javascript user). It calculates the difference between i + 1 and i (or i + 1 / i) and pushes it into a new array. I then use a function to check if every element in the array is the same.

function numberCheck(array) {
  var arithResult = null;
  var geoResult = null;
  var arithCounter = [];
  var geoCounter = [];
  Array.prototype.allValuesSame = function() {
    for(var i = 1; i < this.length; i++) {
        if(this[i] !== this[0])
            return false;
    } return true;
  }
  for (var b = 0; b < array.length - 1; b++) {
    arithCounter.push(array[b + 1] - array[b]);
  }
  for (var i = 0; i < array.length - 1; i++) {
    geoCounter.push(array[i + 1] / array[i])
  }
  arithResult = arithCounter.allValuesSame();
  geoResult = geoCounter.allValuesSame();
  if (arithResult === true) { return "Arithmetic";}
  else if (geoResult === true) { return "Geometric";}
  else { return "-1";}
}
numberCheck([1,2,4,8])
发布评论

评论列表(0)

  1. 暂无评论