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

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

ただいまの
回答率

87.78%

Atcoder "ABC 083 B - Some Sums" コード解説のお願い(JS)

解決済

回答 1

投稿

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

score 2

前提・実現したいこと

下記のコードの解説をお願いしたいです。
const numsのところがわからないのでそこを重点的に教えていただいたら有難いです。(問題文などは理解)
なお下記のものは、AtcoderのABC 083 B - Some Sumsです。
https://atcoder.jp/contests/abc083/tasks/abc083_b
宜しくお願い致します。

該当のソースコード

function main(input) {
    const args = input.split(' ');
    const N = parseInt(args[0], 10),
          A = parseInt(args[1], 10),
          B = parseInt(args[2], 10);

    const nums = Array.from(new Array(N), (v, i) => ++i).filter((i) => {
        var n = i.toString().split('').reduce((p, c) => p + parseInt(c), 0);
        return (n >= A && n <= B);
    });

    console.log(nums.reduce((p, c) => p + c, 0));
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));

試したこと

各関数について全て調べた

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

ラムダ式、クロージャなどの要素は理解できているとみなして解説します。

Array.from(array,map)
配列arrayからmapで定義した処理を通して新しい配列を作ります。

1引数目:new Array(N)
空の要素の配列を要素N個分作ります。
2引数目:(v,i) => ++i
これは適用するmap関数の中身です。array.map((v,i) => i++)と同じ動作。
mapに入れる関数(今回はラムダ式)の引数は(処理する値, インデックス, もとの配列)の3つがあり、後ろ2つは省略可能。
今回のコードでは3番目の引数が省略されています。インデックス+1したものを新しい配列として作っています。なので処理結果は[1,2,3,4...]になります。

(省略).filter((i) => {...})
filterは配列の各要素を指定の条件で検査し、合格(返り値がtrue)の要素だけで構成した新しい配列を返します。
これもラムダ式になっていますが条件関数本体はクロージャの中にあります。前項で作った配列の中身が1つずつiに入る。
で、クロージャの中身の解説を順番に。

i.toString().split('')
数値iを文字列にして、1文字ずつ分解して配列にする。123['1','2','3']となる。
.reduce((p, c) => p + parseInt(c), 0)
上記で作成した配列の要素それぞれに対し、引数の関数で計算処理を行い、単一の値を返します。
pが処理の戻り値として返したい値で、cは配列の各要素になります。
ここではpにparseInt(c)の値をどんどん足しこんでいく処理になります。p = p + parseInt(c)という処理を配列の要素分繰り返すイメージで良いでしょう。
最後の0pの初期値です。これを設定し忘れるとこの処理は文字列連結になってしまいます。
return (n >= A && n <= B)
filter関数の最後の処理。各桁を足した数nがA以上B以下であればtrue、それ以外ならfalse。
filter関数はこの処理がtrueになった値だけで構成された新しい配列を返します。

最終的にnumsは各桁の総和がA以上B以下の整数の配列となります。

最後、console文の中身。
nums.reduce((p, c) => p + c, 0)
先ほどのreduce関数と同じように配列の中の数値の総和を求めています。

なお、変数名を日本語で書き下し、処理を分割して記述するとこんな感じになります。

var 元の配列 = Array.from(new Array(N), (v, i) => ++i);
var 条件に合致した数字の配列 = 元の配列.filter((数字) => {
    var 各桁に分解した配列 = 数字.toString().split('');
    var 各桁の総和 = 各桁に分解した配列.reduce((合計,数字) => 合計 + parseInt(数字),0);
    return (A <= 各桁の総和 && 各桁の総和 <= B);
});

console.log(条件に合致した数字の配列.reduce((合計,数字) => 合計 + 数字,0));

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/05/21 17:16

    ご回答有難う御座います。
    丁寧でわかりやすく、ご回答の理解とコードの理解ができた時、少し感動しました。。
    本当に有難う御座いました。
    再度このような質問をすると思うので、またご回答いただけたら大変嬉しく思います。
    下記に実際のコードの変換を一つ一つ記載させていただきました。
    ご確認いただけたら有難いです。
    宜しくお願い致します。

    function main(input) {
    //input = "20 2 5"の場合
    const args = input.split(' ');//["20","2","5"]
    const N = parseInt(args[0], 10),
    A = parseInt(args[1], 10),
    B = parseInt(args[2], 10);
    //[20, 2, 5]

    const nums = Array.from(new Array(N)
    // [,,,,,,,N個分]
    , (v, i) => ++i)
    // [
    // 1, 2, 3, 4, 5, 6, 7,
    // 8, 9, 10, 11, 12, 13, 14,
    // 15, 16, 17, 18, 19, 20
    // ]
    .filter((i) => {
    //i=20の場合
    var n = i.toString().split('')
    // ["2", "0"]
    .reduce((p, c) => p + parseInt(c), 0);
    //2 + 0 = 2
    return (n >= A && n <= B);
    //2 >= A && 2 <= B
    });

    console.log(nums.reduce((p, c) => p + c, 0));
    //条件に適応した配列の数値の総和

    キャンセル

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

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

関連した質問

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