かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JS 配列の要素が全て条件を満たすか調べたい

EX: 配列に含まれる数が全て0 <= N <= 255 かどうか調べたい
次のデータから条件にマッチする配列だけを取り出す。

// 調べる配列の入ったデータ
var data = [
  [ 217, 0, 0, 0 ],
  [ 169, 254, 0, 1 ],
  [ 0, 0, 0, 256 ],
  [ 1, 0, -1, 255 ],
  [ '', 0, 0, 0 ] 
];

forEachだとループの途中でbreakできないっぽい。
なので条件に合わないものがあっても最後までチェックするので無駄があり。

for break

条件に合わない値が出てきたらbreakでループを抜ける方法

var a = [];
d.forEach(function(arr, i) {
  let isOK = true;
  for(let j=0,l=arr.length; j<l; j+=1) {
    let n = arr[j];
    if( typeof(n) !== 'number' || (n < 0 || n > 255) ) {
      isOK = false;
      break;
    }
  }
  if(isOK) {
    a[a.length] = arr;
  }
});
console.log(a); // =>  [ [ 217, 0, 0, 0 ], [ 169, 254, 0, 1 ] ]

Array.prototype.every (ES5)

allPassed = array.every(callback[, thisObject]);
与えられた関数によって実行されるテストに配列のすべての要素が合格するかどうかをテストします。
出典: [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every:title]

callbackが1つでもfalseを返した時点でループから抜ける

d.forEach(function(arr, i) {
  let callback = function(i) {
    return (typeof(i) === 'number' && (i >= 0 && i <= 255) );
    // 条件に合わないの否定でもOK
    // return !(typeof(i) !== 'number' || (i < 0 || i > 255) );
  };
  if( arr.every(callback) ) {
    a[a.length] = arr;
  }
});
console.log(a); // => [ [ 217, 0, 0, 0 ], [ 169, 254, 0, 1 ] ]

Array.prototype.some (ES5)

array.some(callback[, thisObject]);
与えられた関数によって実行されるテストに合格する要素が配列の中にあるかどうかをテストします。
出典: [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/some:title]

callbackが1つでもtrueを返した時点でループから抜ける

d.forEach(function(arr, i) {
  let callback = function(i) {
    // NGな条件式を返せばOK
    return (typeof(i) !== 'number' || (i < 0 || i > 255) );
  };
  // NGに全くマッチしなければ(falseなら)、全ての値が条件を満たしている
  if( !arr.some(callback) ) {
    a[a.length] = arr;
  }
});
console.log(a); // => [ [ 217, 0, 0, 0 ], [ 169, 254, 0, 1 ] ]

👆日本語で説明を書くと余計混乱しそう...

感想とまとめ

関数 ループから抜ける条件
for breakキーワードが出てきた段階
every callback関数がfalseを返した段階
some callback関数がtrueを返した段階

every, someを使えばシンプルに書けて良さそう。(条件式返すのがちょっと気持ち悪い気もするけど多分慣れの問題。
タイトルの意味合い的にはeveryだけど、条件式の書きやすさではsomeを使ったほうが良い場合もありそう。
少しづづES5から覚えていきたい...


[参考]

オブジェクト指向JavaScriptの原則

オブジェクト指向JavaScriptの原則

Javascript 自然数の約数の総和を求めたい

プログラム書く仕事が無いので、お脳が腐らないように息抜きにプログラムのパズルをしています。
自然数の約数の総和を求める方法を考えてたのでメモ。

数学的なやつ

自然数NP1a1P2a2素因数分解できる時
Nの約数の総和は

(1+P1+P1**2+...+P1**a1)(1+P2+P2**2+...+P2**a2)...

↓ 例

12 = 2**2 × 3
(1+2+2**2)(1+3) = 7*4 = 28

数学的な公式だと、素因数分解をするとエレガントに約数の総和が求められるのですが、素因数分解を行うプログラムが大変そうだったので別の方法を考えることにしました。

約数をループで探していく

  • N%C === 0 の時 Cは整数Nの約数
  • 1の次は2なので、N自身を除いた最大の約数は N/2 以下の数になる

と、上記の条件から作った関数がこちら

// n: int, n > 0
function divisorSum(n) {
  let c, r = n;
  if(n <= 0) return;
  c = Math.floor(n/2)+1;
  while(c--) {
    if(n%c === 0) r += c;
  }
  return r;
}

divisorSum(12) // => 28

 
N/2以下でループさせれば計算量が多少は少なくて済む気がします。(間違ってたらご指摘ください。数学苦手なので自信はありません。)
他にエレガントな方法や素因数分解するプログラムのヒントがあれば知りたいので教えてください!!
(素因数分解は脳内でどうやって素因数分解しているかを順序立ててトレースすれば良さそうな気もするけど、ループで約数探すより処理が多そうな気が…


[参考]

プログラマのための論理パズル 難題を突破する論理思考トレーニング

プログラマのための論理パズル 難題を突破する論理思考トレーニング

GoogleMaps マウスホイールでのズームしないようにしたい。

シングルページのサイトなどで100%幅でGoogleMapsを表示させるような時、マウスホイールで地図がズームしてしまうと不都合があるので、地図のマウスホイールでのズーム機能をOFFにするメモ。

scrollwheel オプションを使用する。

マウスホイールでのズーム機能はscrollwheelオプションを付けてmapオブジェクトを作成することで変更が可能です。

  • true: マウスホイールでのズーム有効 (デフォルト値)
  • false: マウスホイールでのズーム無効

サンプルコード

function initialize() {
  var mapOptions = {
    center: new google.maps.LatLng(60.1500745,24.978537),
    zoom: 13,
    // disables scrollwheel zooming on the map
    scrollwheel: false
  };
  // Create GoogleMap
  var map = new google.maps.Map(document.getElementById('map'), mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);

See the Pen google map customize by KIKIKI (@chaika-design) on CodePen.

さすがGoogleオプションを追加するだけ。
お店や会社の場所を表示してるとかで予期せぬスクロールでどこ?ってならないように地図上でマウスホイールでスクロールが発生しそうなデザインの時はこのオプションを使用するのがユーザビリティ的にも良いかなぁと思います。


[参考]