質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • JavaScript

    17024questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Javascriptで数字のチェックを行いたい

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 475

hoehoe

score 1

Javascriptで受け取った4桁の数字のチェックを行いたいのですがどのようにすればよいかわかりません。
チェックする内容は続き数字が3つ以上連続であるとエラーを返したいのです。

OK: 8236  <-- "23"の部分は連続しているが2つなのでOK
OK: 2378  <-- "23", "78"の部分は連続しているが2つなのでOK
ERROR: 2348 <-- "234"の部分が3つ連続している
ERROR: 2678  <-- "678"の部分が3つ連続している
ERROR: 4567  <-- "4567"の部分が4つ連続している

前提条件としては数字の中には同じ数字は含まれません。

考え方としては受け取った数字を配列に変換してループで回して・・・???そもそもこの考え方自体が正しいのかもわからず考え方の方向性も思いつかない状況です。

何か良いアイデアがあればご教授頂けると幸いです。よろしくお願いします。

function checkNum(num){
    var arr = num.toString().split('')
    var isValid = true

    for (var i in arr) {
        // チェックロジックでNGならisValid = false
    }

    return isValid
}

checkNum(2346) // false
checkNum(2378) // true
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+5

こんにちは。

この回答の前提として、ご質問にある

続き数字

を、1ずつ増えていく、0以上9以下の整数を項とする数列 と解釈しています。以下の回答の文中に
出てくる "連続する数字" も同様に、1ずつ増える、2個以上の整数を意味します。

上記を前提として、以下のような checkNum の実装を考えました。

/*
 *   checkNum(n)
 *
 *   引数 n : 4桁の整数
 *
 *   返される値
 *        true : n の中に連続する3個以上の数字が含まれない
 *        false : n の中に連続する3個以上の数字を含む
 */
const checkNum = n => [Math.floor(n / 10), n % 1000].every(x => (x - 12) % 111);

// テスト
[
  8236,
  2378,
  2348,
  2678,
  4567
].forEach(e => {
  console.log(`${checkNum(e) ? 'OK' : 'ERROR'}: ${e}`);
});

(※上記のコードを、https://jsfiddle.net/jun68ykt/w5ovpba6/5/  にも上げました。)

上記を実行すると、以下が表示されます。

OK: 8236
OK: 2378
ERROR: 2348
ERROR: 2678
ERROR: 4567

考え方としては、

3桁の整数 x について、x が連続する数字3つで構成されるならば、( x - 12 ) は 111 で割り切れる
( 例: x = 567 とすると、(567 - 12) ÷ 111 = 555 ÷ 111 = 5 余り 0 )

ことを利用しています。具体的には 4桁の数 n から、以下の二つの数(ともに3桁)

  • 先頭3文字の数:  Math.floor(n / 10) 
     
  • 末尾3文字の数:  n % 1000

を作り、これらの

  • 両方ともに、12引いてから 111で割ると割り切れないならば true を
     
  • いずれかが、 12引いてから 111で割ると割り切れるならば false を

返すように、checkNum(n) を作成しました。

 
以上、参考になれば幸いです。


補足

900 から 12を引くと 888で、888 は 111で割り切れます。
従って、たとえば 9001 は連続した3つの数を含んでいなくても、
上記回答の checkNum(9001) は falseを返しますが、
ご質問の中に

前提条件としては数字の中には同じ数字は含まれません。

とあるので、 9001 のほか、 9008 や 2900 などは0 を2つ含むので、
チェック対象の数(checkNum(n) の引数 n )としては考慮していません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/21 19:14

    ご回答有り難うございます。
    「3桁の整数 x について、x が連続する数字3つで構成されるならば、( x - 12 ) は 111 で割り切れる」
    すごい!数学的に成り立っている!とても参考になりました。

    キャンセル

checkベストアンサー

+4

続き数字が3以上と言うことなので。(987とかは入れてないけど)

function checkNum( num ) {
    return ! /012|123|234|345|456|567|678|789/.test( num );
}

console.log( checkNum( 2346 ) ); // false
console.log( checkNum( 2378 ) ); // true

Array.prototype.reduce() でも書いてみた。

function checkNum2( num ) {
    const arr = num.toString().split( '' );
    let tmp = 0;
    let count = 0;
    arr.reduce( ( pre, curr )=> {
        if ( Math.abs( pre - curr ) === 1 ) {
          tmp++;
      } else {
          if ( tmp >= 2 ) count++;
        tmp = 0;
      }
      return curr;
    } );
    if ( tmp >= 2 ) count++;
    return count === 0;
}

console.log( checkNum2( 2346 ) ); // false
console.log( checkNum2( 2378 ) ); // true

reduce 使わないほうが良いかな。

function checkNum3( num ) {
    const arr = num.toString().split( '' );
    const l = arr.length
    if ( l < 3 ) return true;
    let prev = arr[ 0 ];
    let tmp = 0;
    for ( let i = 1; i < l; i++ ) {
        if ( Math.abs( prev - arr[ i ] ) === 1 ) {
          tmp++;
      } else {
          if ( tmp >= 2 ) return false;
        tmp = 0;
      }
      prev = arr[ i ];
    }
    return true;
}

console.log( checkNum3( 2346 ) ); // false
console.log( checkNum3( 2378 ) ); // true

ちょっと改良。(ちなみに「同じ数字が出ない」仕様でなくなった場合は Math.abs で処理している部分の符号をチェックする必要がある)

function checkNum4( num ) {
    const arr = num.toString().split( '' );
    const l = arr.length - 2;
    if ( l < 1 ) return true;
    for ( let i = 0; i < l; i++ ) {
      if ( ( Math.abs( arr[ i ] - arr[ i + 1 ] ) === 1 ) && ( Math.abs( arr[ i + 1 ] - arr[ i + 2 ] ) === 1 ) ) return false;
    }
    return true;
}

console.log( checkNum4( 2346 ) ); // false
console.log( checkNum4( 2378 ) ); // true

動くサンプル:https://jsfiddle.net/q7eyp0uh/4/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/21 19:15

    ご回答有り難うございます。なんと!今回の条件だと8種類のパターンのチェックだけでよかったのですね、もっと複雑な考え方でゴールを目指していました。たった一行の正規表現で完結できてしまうとは本当に目からウロコでした。checkNum4の考え方は(かなり漠然とですが)思い描いていたロジックに近かったので今後これを自分で書けるようにがんばって行きたいです。
    reduceは今回は遠慮させていただきます。
    一番最初に回答を頂き、また4種類もの回答例を頂いたのでこちらをベストアンサーに選ばせていただきました。

    キャンセル

+3

続き文字の定義はこれで合ってますか?

  • 不正に該当するのは1個ずつ上昇する数値だけか?(例:111や321や121は全て妥当)
  • 9の次は0になるのか?(例:901は不正)

ひとまず両方正として回答していきます。
偽になる場合は適宜読み替えてください。


考え方としては受け取った数字を配列に変換してループで回して・・・???そもそもこの考え方自体が正しいのかもわからず考え方の方向性も思いつかない状況です。

3文字特定の連番が続いたらアウトなのですよね?
「連番が続いている数」という変数を定義して、for文でループされる度に増やしていくという手法が良いでしょうね。

1文字ずつ判定して、前回の文字列と比較してけば良いでしょう。

アウトになった瞬間return falseを返せばループ内だとしても即刻関数を終了させて戻り値を返しますので、
今回のケースではisValid変数は不要です。

function checkNum(num){
  var arr = num.toString().split('')
  var last = null;
  var count = 0;

  for (var i in arr) {
    var it = arr[i];
    if (!last) {
      // 最初の文字を取得したら連番1とみなす
      count = 1;
    } else if (parseInt(it) === parseInt(last) + 1) {
      // 取得文字が前回の文字より1多い場合、連番カウントを加算
      count++;
    } else if (last === '9' && it === '0') {
      // 取得文字0、前回の文字9の場合は連番とみなしてカウントを加算
      count++;
    } else {
      // 連番じゃなかったんですね、連番カウントは1になる
      count = 1;
    }
    last = it;

    // 連番が3個続いたらfalseを返すのでしたよね
    if (count >= 3) {
      return false;
    }
  }

  // アウトになる連番が出なかったので妥当ということでtrueを返す
  return true;
}

checkNum(1245)
// true
checkNum(1235)
// false

質問文から素直にコードにするとこんな感じのところがゴールになります。
もう少し発展させてエレガントなコードにするとkeiさんのコードになるでしょう。


おまけ: コードを洗練させていく

引き出しのネタとして全く違うアプローチから解いていきます。
JavaScript中級者向けの内容となっていますので、分かる部分だけ持っていってください。

AとBは連番であるというところを抜き出しましょうか
シリアルナンバーと言えばなんか別のモノを指すように思えますが、まぁいいや、isシリアルナンバーという関数を用意します。

function isSerialNumber (a, b) {
  if (a === 9 && b === 0) return true;
  if (b === a + 1) return true;
  return false;
}
isSerialNumber(1, 2) // true
isSerialNumber(9, 0) // true
isSerialNumber(1, 3) // false

続いて、1234という数字列の判定をしていきます。
これは左の数字と、右の数字が連結…つまり1と22と3``3と4文字目の連結を確認して、
2つの連結が同時に起こっている場合は3文字連番が続いているので不正と判断出来ます。

従って下記のような順序でデータを加工できれば判別が可能となります。

  • ["1", "2", "3", "4"]
  • [[1, 2], [2, 3], [3, 4]]
  • [true, true, true]
  • 3 ← trueが連続して続いたMax回数
  • return 3 < 2 ← 2回以上続いたらfalseを返す

JavaScriptの全ての値はプロトタイプというメソッドがひっついています。
質問文のnum.toString().split('')はまさにそれで、JSの全ての型にはStringに変換するtoStringメソッドが用意されており、文字列に変換した後にsplitメソッドを利用して配列型に変換しています。

さらに配列の型には、mapreduceといったメソッドが用意されており、配列の各要素を好きなように加工する事ができます。

mapやreduceはメソッドは関数を引数として要求するので、何度も関数定義を書くことになり行数が増えがちなのですが、
ES2015というバージョンでアロー関数という書き方が使える様になりました。
モダンブラウザではIE11以外のほぼ全てのブラウザで利用可能です。
早速上記の連番判定関数をアロー関数で書き直してみます。
(functionが消えて=>という2文字の矢印を使ってるだけです、1行で値を返す場合は{}を省略出来たりと便利)

var isSerialNumber = (a, b) => {
  if (a === 9 && b === 0) return true;
  if (b === a + 1) return true;
  return false;
}
isSerialNumber(1, 2) // true
isSerialNumber(9, 0) // true
isSerialNumber(1, 3) // false

では、早速データを加工していきましょう。
今回は連番している状態を1、連番ではない状態を0として文字列変換を経由する事で実現させます。
詳細は各行の末尾にどんな値に変換されるかをコメントで記載しました。

var isSerialNumber = (a, b) => {
  if (a === 9 && b === 0) return true;
  if (b === a + 1) return true;
  return false;
}
function checkNum(num){
  var arr = num.toString().split('') // ["1", "2", "3", "4"]
  var maxLength = arr
    .map((it, i) => i === 0 ? null : [parseInt(arr[i - 1]), parseInt(it)]) // [null, [1, 2], [2, 3], [3, 4]]
    .slice(1) // [[1, 2], [2, 3], [3, 4]]
    .map(it => isSerialNumber(it[0], it[1])) // [true, true, true]
    .map(it => it ? "1" : "0") // ["1", "1", "1"]
    .join('') // "111"
    .split('0') // ["111"]
    .map(it => it.length) // [3]
    .reduce((a, b) => Math.max(a, b), 0) // 3
  return maxLength < 2;
}
checkNum(1245) // true
checkNum(1235) // false

そこそこ難解なので興味が出てきたらという感じで学習してみてください。

メソッドチェインを覚えるとこんな感じで値を転がしていけるようになるので慣れたら楽です。
最初はとっつきにくいと思いますので、1行ずつ実行していってみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/21 00:17

    因みに`"0" ? true : false`を評価するとtrueになります。
    なので最初の判定を単に`!last`でよしとしています。

    キャンセル

  • 2018/06/21 19:15

    ご回答有り難うございます。配列の中身を2つずつに分けて考えるのは興味深いアイデアですね。メソッドチェーンも覚えると「値を転がしていける」というのはとても便利だと思いました。
    0 ? true : false // false
    "0" ? true : false // true
    これも興味深いですね。(文字列を三項演算子に入れるとtrueを返す、であっているのかな?)

    キャンセル

  • 2018/06/22 05:01

    三項演算子やIF文はBoolean型をよこせと言ってきます。
    しかし、0や"0"はBoolean型ではないので型変換を行って評価します。

    JSの型変換でBoolean型へ変換されるときの仕様はECMAScriptで決まっています。
    例えばNumber型は0がfalse、1以上でtrueです。
    String型は空文字がfalse、何か入っていれば例え"0"や"false"というfalseになりそうな値もtrue扱いになります。

    キャンセル

  • 2018/06/22 09:09 編集

    > 例えばNumber型は0がfalse、1以上でtrueです。
    仕様上は「引数が+0, -0, もしくは NaN なら false を返し、それ以外なら true を返す」ですね。
    つまり、引数が-1や0.1はなら true を返します。
    http://www.ecma-international.org/ecma-262/8.0/#sec-toboolean
    (自然数を前提としているのかもしれませんが、誤解が生まれるといけないので、念の為)

    キャンセル

+2

reduce使ったことなかったので勉強になりました。 > kei344さん

reduceで1桁づつ差を取った結果を文字列にして
matchで連続数を判定します。

hoehoeさんの意図とは若干外れますが…
以下のサンプルだと、差が1or2が2から3桁続くと その桁を返します。
一致しなけばNULLかな。

let num = 16403234;

var arr = num.toString().split('');
var dif = "";

arr.reduce((pre, curr) => {
    console.log(`${pre} - ${curr}`);
    dif += Math.abs(pre - curr); 
    return curr; //次回のreduceのpreとする。returnしないと、pre=undefind
  });

console.log(arr);  
console.log(dif);  
console.log( dif.match(/[12]{2,3}/).index);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

 要件

  • 「4桁の数値」と「初項 0、交差 1、項数 10 の等差数列」を照合する
  • 等差数列は 901 のように繰り上げされない
  • 等差数列は 987 のように交差 -1 にはならない
  • 「4桁の数値」から「前方3桁」「後方3桁」の数値を切り出し、等差数列と照合して一致したら false、不一致なら true を返す

 コード

'use strict';
function checkNum (number) {
  const progression = '0123456789',
        numberString = String(number).slice(0,4);

  return !progression.includes(numberString.slice(0,3)) && !progression.includes(numberString.slice(1));
}

console.log(checkNum(8236));  // true
console.log(checkNum(2378));  // true
console.log(checkNum(2348));  // false
console.log(checkNum(2678));  // false
console.log(checkNum(4567));  // false

 要件を変えるには

数列を書き換えれば、多少の要件変更には対応できます。

901 の繰り上げを許すなら、

const progression = '012345678901';

交差 -1 の等差数列を許すなら、

const progression = '0123456789876543210';

Re: hoehoe さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/21 19:14

    ご回答有り難うございます。
    ES6のstring.includes()でも簡単に結果が導けるのですね、とても参考になりました。progression の書き換えで「901 の繰り上げ」や「交差 -1 の等差数列」にも対応できるという考え方は今後の参考にさせていただきます。ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    17024questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。