アレがアレでアレ

(できれば)プログラミング関係のことを書きたい

Git diffでShift-JISの文字化けメモ

​ コードがShift-JISの場合、git diffをすると文字化けする。

.git/config.gitattributes​を以下のようにすることで文字化けしなくなった。

.gitattributes .csvの部分はsjisファイルの拡張子を記述

*.csv diff=sjis 

config

[diff "cp932"]
    textconv=iconv -f cp932 -t utf-8
[diff "sjis"]
    textconv=iconv -f sjis -t utf-8

Visual Studio 2017でTypeScriptのコンパイルを無効にする

ASP.NET MVC + TypeScriptでwebを書いていたんですが、 サーバー側の処理だけ動作確認したいっていうときにTypeScriptのソースにエラーが出ているとデバッグができないですよね。

webpack動かせばちゃんとエラーは分かるし、TypeScriptはvscodeで書くからVisual Studio上のコンパイルは無効にしちゃっていいんじゃないかなと。

無効にする方法

.csprojファイルのPropertyGroup内に以下の記述を追加

<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>

これでVisual Studio上でTypeScriptのコンパイルが無効になります。

累積和

競プロで知ったことのメモ。

簡単な概要

累積和とは前処理をすれば O(1)の計算量で、区間の合計を求めることができるアルゴリズム

例えば、長さ N=7の数字の配列があるとする。

 a_{0}  a_{1}  a_{2}  a_{3}  a_{4}  a_{5}  a_{6}
2 6 1 9 5 8 4

 {a_2}から {a_6} までの区間の合計を求めたいというときは、単純に {a_2}から {a_6}までをループ( {a_2} + {a_3} + {a_4} + {a_5} + {a_6})すれば求めることができる。

配列が長かったり、 {a_1} {a_3} {a_0} {a_6} {a_4} {a_6} .....と区間の合計を求める回数が例えば M=1,000,000回もある場合、 O(NM)かかるので処理にとても時間がかかってしまう。

累積和を使うと前処理に O(N)かければ、区間の合計を求める計算量は O(1)で済む。

どんな前処理かというと、以下のような N+1大きい配列を用意する。

 s_{0}  s_{1}  s_{2}  s_{3}  s_{4}  s_{5}  s_{6}  s_{7}
0 2 8 9 18 23 31 35

この配列の中身、 s_nには a_{n-1}までの区間の合計が入っている。

  •  s_1 = a_0
  •  s_2 = a_0 + a_1
  •  s_3 = a_0 + a_1 + a_2
  • ...
  • ...
  • ...
  •  s_n = a_0 + ... + a_{n-1}

この配列を用意すれば、 {a_2}から {a_6} までの区間の合計は {s_7} - {s_2}という式で求めることができる。
 {s_7}には {a_0}から {a_6}の合計が入っているので、 {a_0}から {a_1}の合計が入っている {s_2}を引く。

 {s_7} = {a_0} + {a_1} + {a_2} + {a_3} + {a_4} + {a_5} + {a_6}
   = 35

 {s_2} = {a_0} + {a_1}
   = 8
 35 - 8 = 27となる。

実装

上の例、 {a_2}から {a_6} までの区間の合計を求めるプログラムをC#で実装してみる。

void Sample()
{
    var N = 7;
    var a = new int[7] { 2, 6, 1, 9, 5, 8, 4 };
    var s = new int[N + 1];

    var left = 2;
    var right = 6;

    for (int i = 0; i < N; i++)
    {
        s[i + 1] = s[i] + a[i];
    }

    Console.WriteLine(s[right + 1] - s[left]);
}

webpackを使ってみる

webpack.js.org

前回、Babelについて書きました。
今回はwebpackの使い方をメモ程度のクオリティで書いていきます。

webpackとはなにか

モジュールバンドラというものです。
モジュールバンドラとは複数のJavaScriptファイルをまとめて1つのファイルにするツールのことです。

複数のJavaScriptファイルを1つにまとめると、どんな良いことがあるでしょうか?

  • jsファイルの読み込み順など気にしなくても勝手に依存関係を解決してファイルをまとめてくれる。恐らくこれが1番のメリット。
  • ファイルをまとめることでリクエスト数を減らす。通信回数を減らすことができる。
  • 実行時は1つにまとめるので、気にせず機能ごとにファイルを分割してコーディングできる。 変数名が被っても大丈夫。

などなど、メリットがあります。

ディレクトリ構造

今回は以下のようなディレクトリ構造で進めていきます。

.
├── src
│   ├── app.js
│   ├── factorial.js
│   └── fizzbuzz.js
│
├── dist
│   └── bundle.js
├── node_modules
├── package.json
└── webpack.config.js

webpackの環境構築

以下の環境でやってきます。

$ node --version
v10.15.0
$ npm --version
6.5.0

まずはpackage.jsonを作ります。

npm init -y

必要なパッケージをインストール。

npm install --save-dev webpack webpack-cli

webpack.config.jsというwebpackの設定ファイルを作ります。

const path = require('path');
 
module.exports = {
  mode: 'development',
  entry: './app.js',

  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
};
  • mode: development,production,noneがある。
    • development: 開発用。ビルド時間が短い。
    • production: 本番用。ビルド時間が長い。最小化されたファイルが出力される。
    • none: オプション無効。
  • entry: エントリーポイントの設定。起点となるjsファイルを指定する。 webpackはこのファイルが依存しているモジュールを調べてバンドル(まとめる)してくれる。
  • filename: 出力ファイル名
  • path: 出力先のパス

これで最低限のwebpackの環境ができました。

サンプルのコード

バンドルするJavaScriptを用意します。
サンプルでfizzbuzzと階乗を求めるモジュールを作りました。
これをapp.js上で呼び出します。

fizzbuzz.js

export const fizzbuzz = x => {
  let result = '';
  if (x % 3 == 0)
    result += 'Fizz';
  if (x % 5 == 0)
    result += 'Buzz';

  return result || x;
};

factorial.js

export const factorial = x => {
  if (x === 0)
    return 1;

  return x * factorial(x - 1);
};

app.js

import {fizzbuzz} from './fizzbuzz';
import {factorial} from './factorial';

console.log(fizzbuzz(3));
console.log(fizzbuzz(5));
console.log(fizzbuzz(15));
console.log(fizzbuzz(98));

console.log(factorial(5));

バンドルしてみる

npxコマンドを使用してwebpackを実行します。

npx webpack

npxが使えない環境は

./node_modules/.bin/webpack

実行結果

$ npx webpack
Hash: 9ca0da58fd666451390a
Version: webpack 4.29.6
Time: 99ms
Built at: 03/21/2019 12:07:03 AM
    Asset      Size  Chunks             Chunk Names
bundle.js  5.62 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./app.js] 211 bytes {main} [built]
[./factorial.js] 107 bytes {main} [built]
[./fizzbuzz.js] 156 bytes {main} [built]

特にエラーがなければdistフォルダの中に1つにまとめられたbundle.jsができています。

bundle.js実行

$ node dist/bundle.js
Fizz
Buzz
FizzBuzz
98
120

app.js上で呼び出したモジュールがまとめられ、ちゃんと実行できています。

webpack&Bebelで使う

次にwebpackとBabelと組み合わせて使ってみます。

必要なパッケージのインストール

$ npm install --save-dev babel-loader @babel/core @babel/preset-env
  • babel-loader: webpackでBabelを使うのに必要なパッケージ

webpack.config.jsを以下のように書き換えます。

const path = require('path');
 
module.exports = {
  mode: 'development',
  entry: './src/app.js',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },

  // ↓以下追加
  module: {
    rules: [
      {
        // 処理対象ファイル
        test: /\.m?js$/,
        // 処理の対象外にするディレクトリ
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

moduleというのを追加しました。
ここは「jsファイルはBabelで変換するように。ただし、node_modulesディレクトリ内のjsファイルは無視してね。」という指示を書いています。
node_modulesを除外しないと変換の速度が遅くなったり、エラーになったりするようです。

Babelの設定はbabel.config.jsなどに書くのですが、webpack.config.jsoptionsに書いてしまうこともできます。今回はこっちに設定を書きました。

Babelとwebpackを連携させる設定ができたので、
あとはwebpackを実行すればトランスパイルされているbundle.jsが出力されます。

modeをnoneにすると変換したところがわかりやすいのでnoneで実行します。

$ npx webpack --mode=none

bundle.jsの中身抜粋

/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fizzbuzz", function() { return fizzbuzz; });
var fizzbuzz = function fizzbuzz(x) {
  var result = '';
  if (x % 3 == 0) result += 'Fizz';
  if (x % 5 == 0) result += 'Buzz';
  return result || x;
};

/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "factorial", function() { return factorial; });
var factorial = function factorial(x) {
  if (x === 0) return 1;
  return x * factorial(x - 1);
};

/***/ })
/******/ ]);

わざとらしくアロー関数で書いたとこがトランスパイルされているのを確認できました!

おわり。

Babelを使ってみる

babeljs.io

Babel、どんなツールか知っていたけれど使ったことなかったので試してみます。
webpack + Babelで使うのをよく見ますが、とりあえずBabelだけコマンドラインから使ってみます。

Babelとはなにか

簡単に言うと、新しいJavaScriptの書き方で書いたコードを古い書き方のコードへ変換するツールです。
なぜせっかく新しい構文で書いたのにわざわざ古い方へ変換しなきゃいけないかというと、 ブラウザごとにJavaScriptの新バージョンへの対応状況が違うので、新しい書き方だと動いてくれないブラウザがあるからです。(※IEとかIEとかIEとかね)

ということで、Babelを使って変換すればブラウザが対応してない構文でも気にせずコーディングできます。

Babelの環境構築

実行環境

  • Node.js: 11.10.1
  • npm: 6.7.0

npmで必要なパッケージをインストールします。
インストールする前にnpm init -ypackage.jsonを作っておきます。

$ npm install --save-dev @babel/core @babel/cli @babel/preset-env

設定ファイル

babel.config.jsというファイルを作って、ここにBabelの設定を書いていきます。

const presets =  [
  ['@babel/preset-env', {
    'targets': {
      'ie': '11',
      'chrome': '58'
    }
  }]
];
module.exports = { presets }

使用するプリセット(@babel/preset-env)と、targetsにサポートするブラウザのバージョンを指定します。 指定した環境を最低限サポートするよう変換してくれます。

babeljs.io

Babel実行

試しに以下のJavaScriptを変換してみます。
どれもIE11では対応していないECMAScript2015の構文で書いてみました。

index.js

const add = (a, b) => a + b;

class Person {
  constructor(age, name) {
    this.age = age;
    this.name = name;
  }
  toString() {
    return `name=${this.name}, age=${this.age}`;
  }
}

const numbers = [1, 2, 3, 4, 5];
for (const number of numbers.map(x => x * 2)) {
  console.log(number);
}

次にpackage.jsonにBabelの実行コマンドを登録しておきましょう。
ここでは、srcというフォルダに先程のindex.jsを用意して変換してみます。
-oオプションで変換後のファイルを出力できます。distフォルダに出力することにします。

"scripts": {
  "build": "./node_modules/.bin/babel src/index.js -o dist/index.js"
},

保存したらpackage.jsonがある場所で

$ npm run build

変換後のindex.js

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var add = function add(a, b) {
  return a + b;
};

var Person =
/*#__PURE__*/
function () {
  function Person(age, name) {
    _classCallCheck(this, Person);

    this.age = age;
    this.name = name;
  }

  _createClass(Person, [{
    key: "toString",
    value: function toString() {
      return "name=".concat(this.name, ", age=").concat(this.age);
    }
  }]);

  return Person;
}();

var numbers = [1, 2, 3, 4, 5];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

try {
  for (var _iterator = numbers.map(function (x) {
    return x * 2;
  })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
    var number = _step.value;
    console.log(number);
  }
} catch (err) {
  _didIteratorError = true;
  _iteratorError = err;
} finally {
  try {
    if (!_iteratorNormalCompletion && _iterator.return != null) {
      _iterator.return();
    }
  } finally {
    if (_didIteratorError) {
      throw _iteratorError;
    }
  }
}

はい。ちゃんとアロー関数やクラス、for ofループが変換されています。
for ofループのとこなんかぱっと見た感じ何やってんのか分からないレベルですね...

他にもいろいろ設定があったりするのですが、とりあえずES2015の構文が変換できればいいということで終わりにします。

Raspberry PiにDockerで.NET Core環境を構築してみた

ラズパイでC#を動かしたくて ラズパイ内に.NET Core環境をDockerで構築してみました。

バージョン

  • .NET Core SDK 2.1

ラズパイの環境

Dockerインストール

まずはDockerをインストールします。

以下のコマンド1つでインストールできました。

$ curl -sSL https://get.docker.com | sh
$ docker --version
Docker version 18.06.0-ce, build 0ffa825

これでDockerはインストールできましたが、dockerコマンドがroot権限がないと使えないので以下のコマンドでdockerグループにユーザーを追加します。

$ sudo usermod -aG docker ユーザー名

これでsudoを打たなくてもdockerコマンドを実行することができます。

.NET Coreが動作するコンテナの準備

次は.NET Coreが動作するDockerコンテナを立てます。

色々調べてたらラズパイで動きそうなarm32v7対応のDockerfileが公式にありましたのでこれを使いました。

※追記 Dockerfileのリンクが切れていたので更新しました。
バージョンは3.1です。

github.com

Dockerfileのビルド

先程のURLのDockerfileを使ってビルドし、イメージを作ります。

$ docker build -t dotnet .

コンテナの起動

$ docker run -it --name my-dotnet dotnet

コンテナを起動できたらdotnetコマンドを実行してみます。

# dotnet --version
2.1.302

.NET Coreがちゃんとインストールできているのが確認できました。

サンプルプログラムを動かす

.NET Coreの環境ができたのでサンプルプログラムを動かしてみます。

プロジェクト作成

dotnet newコマンドでプロジェクトを新規作成します。

-oオプションで出力するプロジェクトの配置場所を指定。

今回はコンソールアプリケーションを実行したいのでconsoleを指定しました。
作成できるテンプレートはdotnet new -lで確認できます。

# dotnet new console -o Sample
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on Sample/Sample.csproj...
  Restoring packages for /root/Sample/Sample.csproj...
  Installing Microsoft.NETCore.DotNetAppHost 2.1.0.
  Installing Microsoft.NETCore.DotNetHostResolver 2.1.0.
  Installing Microsoft.NETCore.DotNetHostPolicy 2.1.0.
  Installing NETStandard.Library 2.0.3.
  Installing Microsoft.NETCore.Platforms 2.1.0.
  Installing Microsoft.NETCore.Targets 2.1.0.
  Installing Microsoft.NETCore.App 2.1.0.
  Generating MSBuild file /root/Sample/obj/Sample.csproj.nuget.g.props.
  Generating MSBuild file /root/Sample/obj/Sample.csproj.nuget.g.targets.
  Restore completed in 18.24 sec for /root/Sample/Sample.csproj.

Restore succeeded.

実行すると-oで指定したディレクトリの中にこんな感じでファイルができています。

# ls
Program.cs  Sample.csproj  obj

Program.csの中身

using System;

namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

それではdotnet runコマンドでプログラムを実行してみましょう。
コマンドを実行する前に.csprojファイルがあるディレクトリまで移動します。
もしくは--projectオプションでプロジェクトを指定することもできます。

# cd Sample
# dotnet run
Hello World!

実行までに多少時間がかかるけど正常に動いてくれました!

参照渡し?値渡し?

よくわかっていなかったので調べました。

参考記事

qiita.com

値渡し

C#(というか多くの言語)では通常、メソッドの引数へは値渡しとなる。

値渡しとは変数の値をコピーしてメソッドの引数に渡すこと。

なので値を渡した変数をメソッド内で変更しても、元の変数は変化しない。

public static void Add(int x)
{
    x += 10;
    Console.WriteLine(x); // 10
}

static void Main(string[] args)
{
    int x = 10;
    Add(x);
    Console.WriteLine(x); // 10
}

参照の値渡し

先ほどの例は値型だが、 参照型をメソッドに渡すときも値渡しである。

参照型の場合、変数の参照値コピーしてメソッドの引数に渡している
これを参照渡しと間違いやすいようだが、実際には参照の値渡しである。

メソッドの変数には呼び出し元の変数を指す参照値が入っているので、Addすると呼び出し元の変数もorangeが追加される。

public static void Foo(List<string> words)
{
    words.Add("orange");
    words.ForEach(Console.WriteLine);
}

static void Main(string[] args)
{
    var words = new List<string> { "apple", "banana" };
    Foo(words);
    Console.WriteLine("-----");
    words.ForEach(Console.WriteLine);
}

出力結果

apple
banana
orange
-----
apple
banana
orange

wordsに入っているのはあくまでも参照値のコピーなので、メソッド内で新たなインスタンスを代入し、操作を行っても呼び出し元には影響しない。

public static void Foo(List<string> words)
{
    words = new List<string>();
    words.Add("orange");
    words.ForEach(Console.WriteLine);
}

static void Main(string[] args)
{
    var words = new List<string> { "apple", "banana" };
    Foo(words);
    Console.WriteLine("-----");
    words.ForEach(Console.WriteLine);
}

出力結果

orange
-----
apple
banana

参照渡し

PythonJavaには値渡しのみで参照渡しはないが、C#にはちゃんと参照渡しが存在する。

参照渡しは変数の参照をメソッドの引数に渡している。※コピーではない

参照の値渡しでは不可能だったが、参照渡しは呼び出し元の変数をメソッド内で操作するのと同じことなので、新しいインスタンスを代入するとそれも呼び出し元に反映される。

呼び出し元、メソッドの引数の前にrefを指定することで参照渡しになる。

public static void Foo(ref List<string> words)
{
    words = new List<string>();
    words.Add("orange");
    words.ForEach(Console.WriteLine);
}

static void Main(string[] args)
{
    var words = new List<string> { "apple", "banana" };
    Foo(ref words);
    Console.WriteLine("-----");
    words.ForEach(Console.WriteLine);
}

出力結果

orange
-----
orange

終わり。