8つのボール問題、書き直し(JavaScript手習い)

先ほどの解答(http://d.hatena.ne.jp/torazuka/20130626/balls)を書き直します。

  • 配列Xを配列a, b, cに分割するイディオムを知りたい

単なるArray.sliceでいいのでは、と気づいて書いてみましたが、エラーになってしまいました。 slice(start, end+1)すべきところで、slice(start, num)していたせいでした。(hirataraさんありがとうございます)

exports.solve = function(balls){
	var right = balls.slice(0, 2);
// エラー

仮引数に入ってくる値がArrayかどうか分からない状態ではsliceできない、ということでしょうか。分かりません。

とりあえず、今回は要素が8個固定なので、添え字を元に分割することにしました。

  • 配列a, b, cで、元の配列Xの添え字を保持したい

構造体みたいなのを作りました。thisやnewを使うなとあれほどいわれているのに使ってしまった。

書き直した解答

var _ = require("./lib/underscore-min.js");

exports.ball = function(i, w){
	this.index = i;
	this.weight = w;
	return this;
};

exports.solve = function(balls){

	// 3, 3, 2ずつ取り出して比べる
	var right = balls.slice(0, 3);
	var left = balls.slice(3, 6);
	var other = balls.slice(6, 8);

	var rsum = _.reduce(right, function(memo, num){ return memo + num.weight; }, 0);
	var lsum = _.reduce(left, function(memo, num){ return memo + num.weight; }, 0);

	if(lsum === rsum){
		// 3, 3が釣り合ったら残り2つで比べる
		return other[0].weight < other[1].weight ? other[1].index : other[0].index;
	}
	// 右(左)の方が重ければ右(左)から1つずつ取り出して比べる
	if(lsum < rsum){
		return comp(right);
	} else {
		return comp(left);
	}

	function comp(targets){
		if(targets[0].weight === targets[1].weight){
			return targets[2].index;
		}
		return targets[0].weight < targets[1].weight ? targets[1].index : targets[0].index;
	};
};

テストコード。

var assert = require('assert');
var gb = require("./googleBall.js");

describe('8つのボールから1つだけ重いボールのインデックスを返す', function(){
    it('重いボールが先頭にある場合', function(){
        var ball = gb.ball;
    	var answer = gb.solve([new ball(0, 7), new ball(1, 5), new ball(2, 5), new ball(3, 5), new ball(4, 5), new ball(5, 5), new ball(6, 5), new ball(7, 5)]);
        assert(answer === 0);
    })
    it('重いボールが中央付近にある場合', function(){
        var ball = gb.ball;
        var answer = gb.solve([new ball(0, 5), new ball(1, 5), new ball(2, 5), new ball(3, 5), new ball(4, 7), new ball(5, 5), new ball(6, 5), new ball(7, 5)]);
        assert(answer === 4);
    })
    it('重いボールが末尾にある場合', function(){
        var ball = gb.ball;
        var answer = gb.solve([new ball(0, 5), new ball(1, 5), new ball(2, 5), new ball(3, 5), new ball(4, 5), new ball(5, 5), new ball(6, 5), new ball(7, 7)]);
        assert(answer === 7);
    })
});

ぐぬぬ