全探索 (AtCoder B問題)

What

全探索は、全ての組み合わせを逐一、条件と一致するか確認するアルゴリズムです。

ここの問題を解いていく過程で学んだことや解法を記録しておきます。 qiita.com

Results

全て列挙しなくても解ける問題が多いと感じました。
以下、それぞれの問題に関して、方針や解法を記録しておきます。

ABC144 B_81

atcoder.jp

for文は1回で済みます。
与えられた数値に対して、1から9で割ります。その商が1から9の範囲内にあれば、true...このようにすれば解けます。

ABC150 B_CountABC

atcoder.jp

以下のように、正規表現で解けます (標準入力のプログラムは省略)。
エラー回避のため、マッチする文字列がないときは、空配列を与えるようにしています。

  const input = lines.split('\n')[1]
  console.log((input.match(/ABC/g) || []).length)

ABC122 B_ATCoder

atcoder.jp

入力された文字列の最初から、A, T, C, Gのいずれかの文字があるかどうか確認します。
該当しない文字に当たったら、'\n'で書き換えます。

一旦、配列を結合し、'\n'毎に配列を作りなおし、各要素の大きさだけの配列に変換します。
スプレッド構文を使い、一番大きな要素を出力すれば、完成です。

  let lengthArray = input.join('').split('\n').map(function(val){return val.length})
  console.log( Math.max(...lengthArray) )

なお、スプレッド構文は以下を満たします。配列の各要素を1つずつ取り出して評価したいときに、使えそうです。

console.log( Math.max(...arr) ===  Math.max.apply(null, arr))
//=> true

ABC136 B_Uneven Numbers

atcoder.jp

そんなに難しくないです。桁数 == 文字数が奇数のものを数え上げればできます。

  const input = lines.split('\n').map(Number)[0]
  let count = 0
  for(let i=1; i<=input; i++){
      if(i.toString().split('').length % 2 === 1){
          count++
      }
  }
  console.log(count)

ABC106 B_105

atcoder.jp

与えられた数値までの全数値 (奇数) を求める。求めた数値の約数を数え上げる。上記2つのために、for文を2回使います (または、与えられる数値の範囲が狭いため、if文で条件分けしても良さそうです)。

  const input = lines.split('\n').map(Number)[0]
  let count = 0

  // 入力した数値までの全数字を求める (奇数なのでi+=2)
  for(let i=1; i<=input; i+=2){
          let tmpCount = 0;

          // 求めた数値の全約数を求める
          for(let k=1; k<=i; k++){
              if(i%k === 0){
                  tmpCount++
              }
          }
          if(tmpCount === 8){
              count++
          }
  }
  console.log(count)

ABC120 B_K-th Common Divisor

atcoder.jp

それぞれの約数を求め、共通項をくくればできます。
Node.jsのバージョンが高ければ、includesメソッドで共通項を出力できます。

let divisorAB = divisorA.filter(function(element){return divisorB.includes(element);})

しかし、ABC120では、includesメソッドは使えませんでした。
計算量は少し多くなりますが、以下のように書き換えることもできます。

  var divisorAB = []
  for(var i=0; i<Math.max(divisorA.length,divisorB.length); i++){
    for(var k=0; k<Math.max(divisorA.length,divisorB.length); k++){
      if( divisorA[i] === divisorB[k]){
        divisorAB.push(divisorA[i])
        break;
      }
    }
  }

B問題は一旦これで終了なので、続きはまた後日投稿します。

for of vs for in

What

for文におけるofとinの違い

for (let i = 0; i < xxx.length; i++)で書き直すことで、理解を深める。

Results

まず、用語の導入として、プロパティ名とプロパティを簡単に示します。

ハッシュでは、{プロパティ名: プロパティ}となります。
配列の場合は [プロパティ名]ですが、{配列の要素の番号: プロパティ名}とも見なせます。

const array  = ['yamada', '25', 12]
const hash = {0: 'yamada', 1: '25', 2: 12}

console.log(array[1] == hash[1])
// => true
console.log(array == hash)
// => false

inはプロパティ名を取得

for文でinを使うと、プロパティ名を取得できます。これは、ハッシュや配列、文字列にも適用できます。

const hashObject = {name: 'yamada', age: 25}
const str = 'avcde'

for (let key in hashObject){
    console.log(key)
    // => name age
}

for (let key in str){
    console.log(key)
    // => 0 1 2
}

次のようにも書き直せます。Object.keysメソッドは引数においたオブジェクトのキー (プロパティ名) を取得します。

const hashObject = {name: 'yamada', age: 25}
const str = 'avcde'

for (let i=0; i<Object.keys(hashObject).length; i++){
    console.log(Object.keys(hashObject)[i])
}

splitHash = str.split('')
for (let i=0; i<splitHash.length;i++){
    console.log(i)
}

ofはプロパティを取得

配列や文字列にしか使えません。

const hashObject = {name: 'yamada', age: 25}
const arrayObject  = ['yamada', '25', 12]
const str = 'abc'

for (let value of hashObject){
    console.log(value)
    // type error
}

for (let value of arrayObject){
    console.log(value)
    // => yamada 25 12
}

for (let value of str){
    console.log(value)
    // => a b c
}

for (let i=0; ...)での書き換えは、inでの書き換えと似ているため、省略します。ofの代わりに、forEachで書き直すこともできます。inとofはプロパティ名 (キー) を取り出したいのか、プロパティ (バリュー) を取り出したいのかで使い分けます。

/[^\w]/g != new RegExp('[^\\w]', 'g')

What

正規表現の作り方について、理解に手間取ったので、まとめておきます。

文字列 Hi Bob!!をHiBobとして表示したい (空白や特殊文字を排除したい) 場合、以下の2通りの方法があります。

const word = 'Hi Bob!!';
reg1 = /[^\w]/g;
regResult1 = word.replace(reg1, '');
console.log(regResult1)
// => HiBob
const word = 'Hi Bob!!';
reg2 = new RegExp('[^\\w]', 'g');
regResult2 = word.replace(reg2, '');
console.log(regResult2)
// => HiBob

与える結果が同じなので、reg1とreg2は同じものだと考えましたが、以下の結果から分かるように両者は異なるものみたいです。

console.log(reg1 == reg2)
// => false

Solution

答えは、公式ドキュメントにありました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions

前者の//で囲む方は正規表現リテラルといい、スクリプトをロードした時に、コンパイルされる正規表現。そのため、正規表現が変化しない場合にパフォーマンスが良い。後者はRegExpのコンストラクタ関数を用いた方法で、該当するコードが実行されるたびにコンパイルされる正規表現。そのため、正規表現が変化する場合にパフォーマンスが良い (正規表現リテラルと異なり、全てのコードをリロードしなくて良いため)。

結論として、

両者とも、与える結果は同じだけど、正規表現のコンパイルのやり方が異なるので、等しくない。

以下正規表現を作成するときに役立つ部分だったので、控えておきます。
正規表現の引数について gとか
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp
正規表現のマッチャについて
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions

Supplement

正規表現^a[^a]の違い

前者は先頭の文字がaだったらマッチするのに対し、後者はaがなかったらマッチする (補集合)。どちらもgを使っていないため、1個マッチした時点でそれ以降は判定しません。

const againLower = 'again'
const againUpper = 'Again'
regAgainLower = againLower.replace(/^a/, 'x')
regAgainUpper = againUpper.replace(/^a/, 'x')
console.log(regAgainLower)
// => xgain
console.log(regAgainUpper)
// => Agxin
const againLower = 'again'
const againUpper = 'Again'
regAgainLower = againLower.replace(/[^a]/, 'x')
regAgainUpper = againUpper.replace(/[^a]/, 'x')
console.log(regAgainLower)
// => axain
console.log(regAgainUpper)
// => xgain

Nuxt + Firebase | キャッシュを保存しない設定

What

Nuxtでアプリ開発をした際、キャッシュが残り、結果が反映されないことがありました。そのため、キャッシュを保存しない設定を加え、対処しました。

Solution

nuxt.config.jsに以下を追記します。

... ,
serverMiddleware: [
  '~/api/headers.js'
],
...

api/headers.jsに以下を追記します。

module.exports = function(req, res, next){
  res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
  next()

確認はできていませんが、以下をHeaderに追加するやり方でも良さそうです。

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">

参考
https://github.com/nuxt/nuxt.js/issues/2554
https://www.tagindex.com/html_tag/page/meta_pragma.html

Can't verify CSRF token authenticity.

What

RailsAPIを扱っている際にログに出現しました。

Solution

ただ無効化する方法

Qiita等でよくあるやり方は、CSRFを無効化する方法です。
Railsのヘルパーを使っている場合は、トークンが発行されますが、コンポーネント化するために、生HTMLを使用すると、トークンが発行されず、上記の警告が出ます。
そのため、APIを使用しているコントローラーにて、CSRFを無効化すれば、解決するという発想です。

- protect_from_forgery
+ skip_before_action :verify_authenticity_token

[参考]
https://qiita.com/nishina555/items/4ffaf5cc57a384b66230

トークンを発行する方法

CSRFを無効化すると、何のためにトークンを付けてるのかなとなります。
axiosを使っているならば、任意のメソッドに以下を追記すれば、トークンを発行するため、上記エラーも解決します。

createPost: function(){
  axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
  };
 ...
  axios.post(...){ 
  ...
}    
    

Nuxt + Firebase

What

ローカルである程度開発し、デプロイして確認しているのですが、ちょいちょいコマンドを忘れるため、そのメモを残しておきます。

Lists

Nuxtアプリを起動する
アプリのあるディレクトリにて、以下を実行します。権限関連でエラーが起きる場合は、適宜権限を与えておくか、sudoで実行しておくと良いです。

$ npm run dev

ビルドし、結果を生成する。
Nuxt.jsはRailsなどと異なり、自動ビルドされないため (もしかすると、やり方があるかもしれない)、コマンドを打つ必要があります。

$ npm run build
$ npm run generate

デプロイ!
デプロイに成功しても、アプリの見た目が変わらない場合は、ビルドで失敗している可能性があります。

$ firebase deploy

S3の設定

What

画像ファイル等をAWSの別コンテナに保存し、ec2コンテナを変更しても大丈夫なようにする。
具体的には、carrierwave利用時の画像保存先をS3にします。

Do

Localの設定

config/carrierwave.rbというファイルを作成し、以下記述します。uploaders/image_uploader.rbに書いても良いですが、同じ記述がないようにします。

require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  if Rails.env.production?
    config.storage :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = ENV['AWS_S3_PACKET']
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
      region: ENV['AWS_REGION'],
      path_style: true
    }
  else
    config.storage :file
    config.enable_processing = false if Rails.env.test?
  end
end

環境変数については、credentials.ymlかec2コンテナに環境変数用のファイルを作成しておきます。

AWSコンソールでの設定

S3でパケットを作ります。この時のパケット名が、ENV['AWS_S3_PACKET']で、リージョンがENV['AWS_REGION']です。リージョンはURLのregion=<リージョン名>からも確認できます。

サービス利用者に擬似的に権限を与え、S3に保存するように設定します。IAMで、画像保存を許可する実体のないユーザーを作成します。アクセスの種類はプログラムによるアクセスです。次に進み、権限をアタッチします。 f:id:hellow_takuya:20200322234556p:plain

ユーザーの作成が終わると、アクセスキー (ENV['AWS_ACCESS_KEY_ID']) とシークレットキー (ENV['AWS_SECRET_ACCESS_KEY']) が表示されます。ユーザー名を選択し、ARNを保存しておきます (画像のユーザーは使用していないため、問題ありません。ご心配なく)。 f:id:hellow_takuya:20200322235846p:plain

次に、アクセスポリシー > パケットポリシーにて、以下を記述します。

{
    "Version": "2012-10-17",
    "Id": "Policy1544152951996",
    "Statement": [
        {
            "Sid": "Stmt1544152948221",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<ユーザーのARN>"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<パケット名>"
        }
    ]
}

画像が保存されると、S3 パケット内でディレクトリが作成されるようになります (ちなみにローカルでは、public配下です)。