【问题标题】:Iterate first x elements of an associative array迭代关联数组的前 x 个元素
【发布时间】:2016-01-09 02:29:42
【问题描述】:

具有 12 个元素的关联数组;

 this.rolls = {1:[], 2:[], 3:[], 4:[], 5:[],
                6:[], 7:[], 8:[], 9:[],10:[], 11:[], 12:[]};

获取前 10 个元素之和的最有效方法是什么。下面的代码目前对所有元素求和;

  var sum = 0;
  for (var k in this.rolls) {
    vals = this.rolls[k];
    for (var i=0; i<vals.length; i++) {
      sum += vals[i] || 0
    };
  };
  this.score = sum

前 10 个元素是:

 this.rolls = {1:[], 2:[], 3:[], 4:[], 5:[],
                    6:[], 7:[], 8:[], 9:[],10:[]};

这里是完整的代码:

function Game() {
  this.score = 0;
  this.frameOver = false;
  this.rolls = {1:[], 2:[], 3:[], 4:[], 5:[],
                6:[], 7:[], 8:[], 9:[],10:[], 11:[], 12:[]};
  this.currentFrame = 1;
  // this.lastFrameStrike = false;
  // this.lastFrameSpare = false;
  // this.isStrike = false
};

Game.prototype.roll = function(pins) {
  this.strikeOrSpare(pins);
  this.bonusDistributor(pins);
  this.rolls[this.currentFrame].push(pins);
  this.scoreUpdater(pins);
  this.frameHandler(pins);
  this.nextFrameBonus(pins)
};

// --------------------------------------------------

Game.prototype.strikeOrSpare = function(pins) {
  if (pins === 10) {
    this.isStrike = true;
    this.frameOver = true
  }
  else if (this.rolls[this.currentFrame][0] + pins === 10) {
    this.isSpare = true;
    this.frameOver = true
  };
};

// --------------------------------------------------

Game.prototype.bonusDistributor = function(pins) {
  if(this.wasSpare) { this.addToLastSpare(pins) };
  if(this.wasStrike) { this.addToLast(pins) };
  if(this.wasStrike2 && this.currentFrame > 1) { this.addToLastAgain(pins) };
};

// --------------------------------------------------

Game.prototype.addToLast = function(pins) {
  this.rolls[this.currentFrame - 1][0] += pins
};

Game.prototype.addToLastAgain = function(pins) {
  this.rolls[this.currentFrame - 2][0] += pins
};

Game.prototype.addToLastSpare = function(pins) {
  this.rolls[this.currentFrame - 1][1] += pins;
  this.wasSpare = false
};

// --------------------------------------------------

Game.prototype.scoreUpdater = function(pins) {
  var sum = Object.keys(this.rolls).sort(function (a, b) {
      return (+a) - (+b);
  }).slice(0, 10).reduce(function (p, c) {
      return p + this.rolls[c].reduce(function (p, c) {
          return p + c;
      }, 0);
  }, 0);
};

Game.prototype.frameHandler = function(pins) {
  if (this.frameOver) {
    this.currentFrame++; this.frameOver = !this.frameOver
  } else {
  this.frameOver = !this.frameOver;
  };
};

Game.prototype.nextFrameBonus = function(pins) {
  if (this.isSpare) {
    this.wasSpare = true;
    this.isSpare = false
    if (this.wasStrike) {
      this.wasStrike = false;
      this.wasStrike2 = true
    }
  } else if (this.isStrike && this.wasStrike) {
    this.wasStrike2 = true
  } else if (this.isStrike) {
    this.isStrike = false;
    this.wasStrike = true
  } else if (this.wasStrike) {
    this.wasStrike = false;
    this.wasStrike2 = true
  } else if (this.wasStrike2) {
    this.wasStrike2 = false
  };
};

// --------------------------------------------------

【问题讨论】:

  • 前 10 个元素是什么意思?你能说得更具体点吗?
  • this.rolls 包含12个元素,需要前10个元素之和
  • 我们在谈论一个关联数组(键值对)你期望哪 10 个元素?
  • 不保证对象中的属性顺序...
  • 您所拥有的对象文字中没有first 10。要么需要适当的数组,要么为所需的属性键定义标准

标签: javascript arrays loops iterator iteration


【解决方案1】:

您遇到的第一个问题是this.rollsObject,而不是Array,因此for (var k in this.rolls) 不能保证按顺序枚举键。所以要解决的第一个问题是取前 10 个键,将它们转换为数字,然后对它们进行排序。这里我使用了所有原生的ArrayObject 方法:

var rolls = this.rolls;
var sum = Object
  // Get all keys
  .keys(rolls)
  // Convert string keys to integers
  .map(function (key) { return parseInt(key, 10); })
  // Sort in ascending order
  .sort()
  // Take the first 10
  .slice(0, 10)
  // Get the arrays for each key
  .map(function (key) { return rolls[key]; })
  // Merge all arrays into one array
  .reduce(function (allNumbers, array) { return allNumbers.concat(array); }, [])
  // Sum all numbers
  .reduce(function (sum, number) { return sum + (number || 0); }, 0);

【讨论】:

  • 你不能在map()中使用this.rolls
  • 是的,我习惯使用箭头函数。已修复,谢谢。
【解决方案2】:

对对象键进行排序和过滤,然后使用它们将数组归约为和

var rolls = this.rolls;
var sum = Object.keys(rolls).sort(function (a, b) {
    return (+a) - (+b);
}).slice(0, 10).reduce(function (p, c) {
    return p + rolls[c].reduce(function (p, c) {
        return p + c;
    }, 0);
}, 0);

DEMO

【讨论】:

  • 你不能在reduce()里面使用this.rolls
  • @SheraliTurdiyev 次要网站..thx。不知道为什么它值得一票否决,演示版工作正常
【解决方案3】:

已编辑:您的示例中有一个错误。您不能在forEach 中使用thisrolls。声明它(var self = this; 或者我的版本是var rolls = this.rolls; 外面)

我建议使用以下代码来计算总和:

var sum = 0;
var rolls = this.rolls;
Object.keys(rolls).forEach(function (key, i, array) {
    if (i < 10) {
        var item = rolls[key].slice();
        while (item.length) {
            sum += item ? Number(item.shift()) : 0 + item ? Number(item.pop()) : 0;
        }
    }
});
console.log(sum, this.rolls);
this.score = sum;

有你的完整例子:

function Game() {
    this.score = 0;
    this.frameOver = false;
    this.rolls = {1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: []};
    this.currentFrame = 1;
    // this.lastFrameStrike = false;
    // this.lastFrameSpare = false;
    // this.isStrike = false
}

Game.prototype.roll = function (pins) {
    this.strikeOrSpare(pins);
    this.bonusDistributor(pins);
    this.rolls[this.currentFrame].push(pins);
    this.scoreUpdater(pins);
    this.frameHandler(pins);
    this.nextFrameBonus(pins);
};

// --------------------------------------------------

Game.prototype.strikeOrSpare = function (pins) {
    if (pins === 10) {
        this.isStrike = true;
        this.frameOver = true;
    }
    else if (this.rolls[this.currentFrame][0] + pins === 10) {
        this.isSpare = true;
        this.frameOver = true;
    }
};

// --------------------------------------------------

Game.prototype.bonusDistributor = function (pins) {
    if (this.wasSpare) {
        this.addToLastSpare(pins);
    }
    if (this.wasStrike) {
        this.addToLast(pins);
    }
    if (this.wasStrike2 && this.currentFrame > 1) {
        this.addToLastAgain(pins);
    }
};

// --------------------------------------------------

Game.prototype.addToLast = function (pins) {
    this.rolls[this.currentFrame - 1][0] += pins;
};

Game.prototype.addToLastAgain = function (pins) {
    this.rolls[this.currentFrame - 2][0] += pins;
};

Game.prototype.addToLastSpare = function (pins) {
    this.rolls[this.currentFrame - 1][1] += pins;
    this.wasSpare = false;
};

// --------------------------------------------------

Game.prototype.scoreUpdater = function (pins) {
    var sum = 0;
//    var self = this;
    var rolls = this.rolls;
    Object.keys(rolls).forEach(function (key, i, array) {
        if (i < 10) {
            var item = rolls[key].slice();
            while (item.length) {
                sum += item ? Number(item.shift()) : 0 + item ? Number(item.pop()) : 0;
            }
        }
    });
    console.log(sum, this.rolls);
    this.score = sum;
};

Game.prototype.frameHandler = function (pins) {
    if (this.frameOver) {
        this.currentFrame++;
        this.frameOver = !this.frameOver;
    } else {
        this.frameOver = !this.frameOver;
    }
};

Game.prototype.nextFrameBonus = function (pins) {
    if (this.isSpare) {
        this.wasSpare = true;
        this.isSpare = false;
        if (this.wasStrike) {
            this.wasStrike = false;
            this.wasStrike2 = true;
        }
    } else if (this.isStrike && this.wasStrike) {
        this.wasStrike2 = true;
    } else if (this.isStrike) {
        this.isStrike = false;
        this.wasStrike = true;
    } else if (this.wasStrike) {
        this.wasStrike = false;
        this.wasStrike2 = true;
    } else if (this.wasStrike2) {
        this.wasStrike2 = false;
    }
};
var game = new Game();
game.scoreUpdater();

【讨论】:

  • 所以,你应该删除你的反对票,现在,我的回答是正确的
  • .slice(0).slice() 或其他克隆阵列更快。 stackoverflow.com/a/21514254/4365315
  • 谢谢 Sherali,顺便说一句,投反对票的不是我,您的回复很有帮助
猜你喜欢
  • 2013-12-17
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
相关资源
最近更新 更多