如何正确计算数组中的出现次数?

时间:2017-05-18 16:54:22

标签: javascript arrays algorithm

我有一个深度数组(数组数组)。 我试图在不使用任何额外方法和JS设计(如闭包)的情况下创建一个正常函数。

这是一个有效的解决方案(但由于全局变量,这是一个糟糕的解决方案)

  var counter = 0;

  function findArray(array, item) {
      for (var i = 0; i < array.length; i++) {
          if (array[i] == item) {
              counter++;
          } else if (array[i].constructor === Array) {
              findArray(array[i], item);
          }
      }
      return counter;
  }

这是一个 none 工作解决方案,试图避开全局计数器变量。

  function findArray(array, item, counter) {
    for (var i = 0; i < array.length; i++) {
        if (array[i] == item) {
            ++counter;
        }
        if (array[i].constructor === Array) {
            findArray(array[i], item, counter);
        }
    }
    return counter;
}

我还想避免计数器输入参数,因为参数应该只是输入,输出变量不应该在函数参数内。另外,我想避免内置的方法,例如slice等。

注意:不应考虑算法的最佳性能。

有没有办法让计数器在函数内部工作?

函数调用如下所示:

findArray([1,[1,2,3],1,[5,9,1],6],  1,0);

输出应为数字 4 ,在此示例中(整数1是要在数组中搜索的数字)。

5 个答案:

答案 0 :(得分:9)

这是递归的用例。 (以及在ES5中添加的Array.isArray。)findArray可以调用自身来查找数组中数组内的事件:

function findArray(array, item) {
    var counter = 0;
    for (var i = 0; i < array.length; i++) {
        var entry = array[i];
        if (entry == item){
            counter++;
        } else if (Array.isArray(entry)) {
            // Add in the count of occurrences in the array, and any arrays in it
            counter += findArray(entry, item);
        }
    }
    return counter;
}

它也是Array#reduce的用例:

function findArray(array, item) {
    return array.reduce(function(counter, entry) {
        if (entry == item) {
            ++counter;
        }
        if (Array.isArray(entry)) {
            counter += findArray(entry, item);
        }
        return counter;
    }, 0);
}

Array#reduce在数组中的每个条目调用一次回调,在每次调用时传入累加器。累加器的初始值作为第二个参数提供(在某些情况下是可选的,但不是这里);回调返回累加器的更新版本,这是reduce的最终返回值。

答案 1 :(得分:1)

你有正确的想法。您可以修改第一个递归函数,如下所示:

function findArray(array, item) {
  var occurrences = 0;

  for (var i = 0; i < array.length; i++) {
    if (array[i] == item) {
      // Found an occurrence.
      occurrences++;
    } else if (array[i].constructor === Array) {
      // Add all occurrences in the sub-array i
      occurrences += findArray(array[i], item);
    }
  }

  return occurrences;
}


console.log(findArray([1, [1, 2, 3], 1, [5, 9, 1], 6], 1, 0));

或者使用reduce调用缩短它,它与上面的想法相同:

function findArray(array, item) {
  return array.reduce((occur, e) =>
    occur + ((Array.isArray(e)) ? findArray(e, item) : (e == item)), 0);
}

console.log(findArray([1, [1, 2, 3], 1, [5, 9, 1], 6], 1, 0));

答案 2 :(得分:0)

我相信这是最好的解决方案:

const countOccurs = (arr, val) =>
  arr.reduce((prev, curr) => {
    if (Array.isArray(curr)) {
       return prev + countOccurs(curr, val);
    }

    if (curr !== val) {
      return prev;
    }

    return prev + curr;
  }, 0);

console.log(countOccurs([1,[1,2,3],1,[5,9,1],6], 1)); // 4

我们在这里做的是,我们将使用Array.prototype.reduce提供数组并检查值的任何出现。如果数组(curr)的实际值是一个数组,则该函数调用自身以检查它并将结果添加到计数器(prev)。

答案 3 :(得分:0)

使用JSBin:http://jsbin.com/sayimecezo/edit?html,js,console,output

您可以简单地展平嵌套数组,然后只对其进行过滤。 (为方便起见,在这里覆盖原型)。

Array.prototype.countDeep = function (n) {
  return [].concat.apply([], this).filter(function (f) {
    return f === n;
  }).length;
}

console.log(([1,[1,2,3],1,[5,9,1],6]).countDeep(1));
//prints 4

播种到记忆值是微不足道的(虽然没必要);

Array.prototype.countDeep = function (n, seed) {
  return (seed || 0) + [].concat.apply([], this).filter(function (f) {
    return f === n;
  }).length;
}

console.log(([1,[1,2,3],1,[5,9,1],6]).countDeep(1, 200));
//prints 204

答案 4 :(得分:0)

另一个也许更易理解的解决方案:

function sumValues(array) {
    let counter = 0;
    for (let item of array) {
      if (Array.isArray(item)) {
        counter += sumValues(item);
      }
      else {
        counter += item;
      }
    }
    return counter;
  }