読者です 読者をやめる 読者になる 読者になる

Kokudoriing

技術系与太話ブログ

条件式判断でリストを分割する拡張メソッド

何を言ってるのかわからないかもしれませんが、いわゆる文字列のSplitのリスト版というかIEnumerable<T>版というかが欲しい。

var nums = new { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

// -1を区切り数としてリストを分割したい.
// {{1, 2}, {5, 6, 8}, {11, 2, 4, 6}, 9} になってほしい.

リスト分割はIx(Interactive Extensions)でBuffer拡張メソッドがあります。
ただ、これは任意個ごとに分割したIEnumerable<T>を返すんですよねー。

var nums = new { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

nums.Buffer(3).ForEach(x => Console.WriteLine(string.Join(",\t", x)));
// 1,      2,      -1
// 5,      6,      8
// -1,     11,     2
// 4,      6,      -1
// 9

んー、確かに便利なんですが、Func<T, bool>を受け取っていただきたく・・。
というわけで作ってみました。

https://gist.github.com/kokudori/5314509

using System;
using System.Collections.Generic;
using System.Linq;

static class Extentions
{
  public static IEnumerable<IEnumerable<T>> Buffer<T>(this IEnumerable<T> source, Func<T, bool> func)
  {
    while (source.Any())
    {
      yield return source.TakeWhile(x => !func(x));
      source = source.SkipWhile(x => !func(x)).Skip(1);
    }
  }
}

class Program
{
  static void Main(string[] args)
  {
    var nums = new[] { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

    nums.Buffer(x => x == -1).ForEach(x => Console.WriteLine(string.Join(",\t", x)));
  }
}

// output:
// 1,      2
// 5,      6,      8
// 11,     2,      4,      6
// 9

これなんでIxに入ってないんだろ。
もしかして車輪の再発明しちゃってる・・?

npmとpackage.json使い方

node.jsと言えばnpmですよ。
それくらいnpm素敵です。RubyのBundlerとかvimのVundleとかみたく素敵です。

まずはnpmの作法というか、思想というか。
いや、npm含めnode.js初心者なので間違ってたらこっそり教えていただければ幸いです。。

npmはローカルインストールとグローバルインストールがあります。
npm install hogehoge
がローカルインストール。
この場合、作業ディレクトリのnode_modulesディレクトリにローカル環境が出来て、そこにインストールされる。
デフォルトがローカルインストールなので、個々のプロジェクト毎に環境持てよということなんでしょう。

npm install -g hogehoge
でグローバルインストール。
グローバルインストールは~/node_modulesにグローバル環境を構築し、そこにインストールします。
よっぽど普遍なやつはそこにインスコしておけばOKってわけですね。

でもこれだと普段使うけどグローバルインストールはちょっと・・ってライブラリのインストールがめんどいですね。
そこでpackage.jsonですよ。
package.jsonはnode環境のマニフェストファイルみたいなもので、まぁBundlerやらVundleやらのあれです。
package.jsonには開発で使う依存ライブラリと本番で使う依存ライブラリを書けます。
npm install
すると開発版ライブラリがローカルインストールされます。便利!

なのでGitHubとかで開発する時とかめちゃくちゃ便利ですね。
そういう背景からグローバルインストールはなんとなく嫌われる背景にありそう。
グローバルライブラリで依存とかしてたらめんどいですしね。

開発の流れとしては、

  1. package.jsonを書く
  2. どこかにホスティングしつつてきとーに開発
  3. 作業ディレクトリとか消えてもへーき
  4. git pullしてnpm installで開発再開
  5. npm startで環境構築
  6. npm testでお手軽テスト

別のOSSとかでフォークして色々いじってやるぜーって時も
git pull
npm install
npm start
npm test
でなんとかなるのは素敵ですね。

というわけでpackage.jsonの書き方備忘録。
package.json自体は
npm init
で簡単に作れます。

{
  // プロジェクト名. 必須項目.
  "name": "hogehoge",
  // プロジェクト概要. npmとかで公開するなら書いた方がいいんじゃないでしょーか.
  "description": "hogehoge is piyopiyo.",
  // プロジェクトバージョン. 必須項目.
  "version": "0.0.1",
  // まんま. プロジェクトのホームページ.
  "homepage": "https://github.com/kokudori/xxx",
  // 作者情報. npmで公開する時は必須?
  "author": {
    "name": "kokudori",
    "email": "kokudori@めあど"
  },
  "repository": {
    // バージョン管理システムの情報. gitとか.
    "type": "git",
    // リポジトリのURL.
    "url": "git://github.com/kokudori/xxx.git"
  },
  "bugs": {
    // バグ報告の場所. GitHub使ってるならissuesページとか.
    "url": "https://github.com/kokudori/xxx/issues"
  },
  "licenses": [
    {
      // ライセンスタイプ. BSDとかMITとか.
      "type": "MIT",
      // ライセンス条文が書いてあるファイルのURL.
      "url": "https://github.com/kokudori/xxx/blob/master/LICENSE-MIT"
    }
  ],
  // 最初に読まれるファイル. エントリポイント.
  "main": "xxx.js",
  "engines": {
    // 依存するnodeのバージョン.
    "node": ">= 0.8.0"
  },
  // 各種 npm xxx で実行されるスクリプト. testとstartあたりがメジャーなのでそこあたりは書いたほうが良さ気?
  "scripts": {
    // npm testで実行される.
    "test": "nodeunit xxx.js"
  },
  // 開発版で依存してるライブラリ. テストで使うとかそんなやつ.
  // npm install でインストール or アップデートされる.
  "devDependencies": {
    // xxxのバージョン0.0.1に依存
    "xxx": "0.0.1",
    // yyyのバージョン0.0.2以上に依存
    "yyy": "~0.0.2"
  },
  // 本番版で依存してるライブラリ.
  "peerDependencies": {
    "xxx": "0.0.1"
  },
  // npmで公開する時とかで使われるキーワードというかタグというか.
  "keywords": [
    "hoge", "piyo"
  ]
}