RubyのcombinationをSwiftでも使いたい
2016年9月15日追記
Swift 3.0 に対応させました。
めちゃくちゃ久しぶりに Swift 触ったわ。。。
追記ここまで。
---
最近codeIQの問題にSwiftでもちょくちょく挑戦してます。
それまでRubyで解くことが多かったので、配列操作のあれが無いこれが無いといった感じで不便さを満喫しております。
combination
とrepeated_combination
はその中でも特に良く使うのでSwift版を作りました。
stack overflowから拾ってきたコード
ググってたらすでに良い感じのコードがあった。
Rubyのrepeated_combinationと同じように動く。
stack overflow : Apple Swift - Generate combinations with repetition
func combos(var array: Array, k: Int) -> Array<Array> {
if k == 0 {
return [[]]
}
if array.isEmpty {
return []
}
let head = [array[0]]
let subcombos = combos(array, k - 1)
var ret = subcombos.map {head + $0}
array.removeAtIndex(0)
ret += combos(array, k)
return ret
}
シンプルで分かりやすいのですが、遅い。
再帰呼び出しを使って配列をちぎっては投げを繰り返しているので、大量に配列を扱うことになりコストが高くなっているのだと思います。
forループで書きなおす
forループで書き直したら約8倍速くなりました。
できるだけRubyと同じように使えるようにしました。
だったらRuby使えばいいじゃんていうね、ありがとうございます。
基本的な使い方
let a = [1, 2, 3, 4]
println(combination(a, 1)) // => [[1], [2], [3], [4]]
println(combination(a, 2)) // => [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
println(combination(a, 3)) // => [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
println(combination(a, 4)) // => [[1, 2, 3, 4]]
println(combination(a, 0)) // => [[]]
println(combination(a, 5)) // => []
配列のインスタンスメソッド
// Array method
println(a.combination(3))
// => [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
引数にブロック(クロージャ)を渡す
// with closuer
a.combination(2){ println($0) }
// =>
// [1, 2]
// [1, 3]
// [1, 4]
// [2, 3]
// [2, 4]
// [3, 4]
let chrs = ["h", "e", "l", "o", "!"]
chrs.repeatedCombination(6){ combo in
if join("", combo) == "hello!" { println(combo) }
}
// => [h, e, l, l, o, !]
Light Tableについて
Light Table使ってます。
Light Tableってどのくらい使われてるんだろう?
twitterのタイムラインを見てるとSublime TextとかAtom関連のつぶやきは良く見かけるけど、Light Tableの事はほぼ見ない印象。
なのでLight Tableのいいところを紹介します。
Evaluation(即時実行)
これがLight Table最大の特徴だと思うんですけど、エディタの中でcmd + enter
を押すと即座にそのコードを実行出来ます。
実際に自分で試してみた範囲だと、
などを実行出来ます。他にも、
などたくさんのプラグインがありました。(これらは実際に試してないので、シンタックスハイライトだけの物もあるかも)
使い方はcmd + enter
が基本です。
JavaScriptの場合はカーソルのある文やブロック、関数などの単位で実行されます。
行単位で、もしくはより細かく選択した範囲のみを実行することも出来ます。
- 行単位でeval!
- 選択範囲でeval!
実行される範囲(JSの場合)
- カーソルのある行の先頭から、一つの式として値を評価できるところまでを実行する。
行の途中でセミコロンがあるとそれ以降は実行しない。
- forブロック行にカーソルがある場合は、そのforブロックが実行される。
- 関数宣言行にカーソルがある場合は、関数宣言が実行される。
- 関数式の代入でも同じ。
- でも即時関数はなぜかブロック単位で実行されないので、選択してあげる必要がある。
スコープを作るために即時関数で包む用途が多いから、敢えてそうしているのかもしれない。
関数の動作テスト
たとえばRubyやCoffeeScriptなんかだと、
5行くらいの関数を書く→その場で実行してテストする
みたいな使い方を良くします。
とりあえずその場で動作を確認できるので相当便利です。
どこでもプレイグラウンド
cmd + enter
で実行出来るということは、いわば編集中のあらゆる場所でプレイグラウンドできちゃうということです。
ビルトインライブラリや言語の仕様など、しばらく触っていないとうろおぼえなことも多いですよね?そんな時すぐにその場で確認できるので超便利です。
0
の真偽値ってどっちだっけ?って思ったら…
- Rubyの場合
- JavaScriptの場合
って確かめられるぅ。
- JSのオーバーフロー
計算用紙
どこでもプレイグラウンドのように使えるということはすなわち、計算用紙の様に書捨ての計算をどんどん実行できるということです。
電卓のような感覚で気軽に計算できちゃう。
ブラウザの開発ツールみたいに使える
各種ブラウザの開発ツールのように使うことが出来ます。
Light Table内でブラウザを起動することで、そのページ上でJS、Coffeeのコードを実行することが出来ます。
これは次に紹介するWatch機能とも関連する部分です。
Watch(監視)
これはJS、coffeeでしか試してませんが強力な機能です。
おそらくRuby, Clojure, ClojureScriptでも利用出来ます。
基本的にはEvaluationと一緒ですが、あらかじめ選択しておいた範囲を監視して、
その部分が実行されると値を右に表示してくれます。
監視したい範囲を選択後、alt + w
でWatch出来ます。
これをブラウザタブと連携して使うことで、強力なデバッガとして使うことが出来ます。
たとえば、jQueryを使ってるサイトだと… みたいな事もできる。
ltWatch関数(名前はなんでも良い)を作っておくデバッグ方法
あらかじめグローバルにltWatch
という関数を定義する、
名前はLight TableのWatchで使うからltWatch
。
下のようなコードを別ファイルにして読み込ませておくと便利、他のコードより先に読み込ませる。
(jQuery等他のライブラリを拡張する場合はそれより後)
ltwatch.js
function ltWatch() {
}
jq-ltwatch.js
//jQuery用
jQuery.fn.extend({
ltWatch: function () {
return this;
}
});
空の関数を宣言しておいて、Watchしたいタイミングで中身を実装、Evaluationすることで上書きします。
監視したい対象のオブジェクトなり、変数なりをltWatch
関数に渡しておけばこれを監視できます。
this
の値を監視するのも便利です。
jQueryのメソッドチェーンの中身も覗くことができます。
これ実はLight Tableに限らず、chromeとかのデバッガでもメソッドチェーンの途中にブレークポイントを設定できるようになるので便利です。
アニメーションの更新やイベントのコールバック関数を監視
Coffee Script
そしてこれらの機能はすべてCoffee Scriptでも使えます(要プラグイン)。
Light TableでEvaluationするコード以外はちゃんとコンパイルしないと当然反映されないので、
gulpのwatchタスクでソースファイルを監視、コンパイルしながら使うと快適です。
プラグインマネージャが便利
AtomやSublimeTextと同じようにプラグインマネージャがあって、簡単にインストール、アンインストール、アップデートができます。
見た目
良い。すごく良い。
好きではない所
- 検索、置換で正規表現が使えない
ぐらいです。
最近の状況
最近は新しいプラグインが増えてない印象。
Swiftのプラグイン、Atomでは速攻で出ましたよね。Light Tableでも出て欲しいナー(自分では作れない)。
追記: 2015/5/27
公式ページのリンクです。
Ruby, RSpec, CoffeeScript, Node.js, gulp, browserify
もろもろはじめました。
何を書いていいのか分からなくなるので、メモはこまめに取らないとダメですね。
ザクッとした感想(雑感)
あれこれ悩んでいるより、とにかく触ってみるのが一番だなと思いました。
新しかったり、自分の知らない技術の紹介とかを見て、興味を持ったらとりあえずREADME.mdを読んで動かしてみると。
テスティングフレームワークもタスクランナーも、ひとつ触ってみると俄然意味が分かるようになります。
というか今まで意味全然分かってなかったです、ありがとうございます。
- Ruby
- とにかく書いてて気持ち良い(JSと比べて)
- リファレンスのメソッドとか見てるとこんな便利なものまで!(JSしか知らないので)
- クラス、proc、スコープの範囲とかはなんとなくしか分からないのでこれから勉強します
- RSpec
- codeIQのある問題で使われていたのがきっかけ
- テストってそれまでのイメージよりはずっと簡単に導入出来るんだなと思った
- もっと早く使えばよかったです
- CoffeeScript
- Node.js
- coffeeを使うためにようやくインストール
- いままで散々見てきたpackage.jsonの意味がようやく分かった
- gulp
- coffeeを毎回コンパイルするの大変だなと思ったらやる気出てきた
- 結局gruntはそのうち、そのうちでを使うことなかった
- browserify
- nodeのmoduleの概念が分かったことで何が有難いのかようやく理解
参考にした有難きリンクたち
ほんとに有難いです。
- Ruby
- オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル
- 困ったらとにかくこれで調べられる、なんでも載ってる。
文法の復習をはじめ、組み込みライブラリなどをよく読む。 - 若手エンジニア/初心者のためのRuby 2.1入門 - @IT
- rvmを使ったインストールをはじめ、頻繁に使われるメソッドや文法からイイ感じに教えてくれる有難い連載。
2014/7/12現在まだ連載中です。
- CoffeeScript
- CoffeeScript基礎文法最速マスター - infinite roop
- JavaScriptとの違いとかを押さえつつ、文法をざっくり解説していて有難い。
- CoffeeScript 言語リファレンス - sappari wiki
- coffeeの文法をがっつり解説しています。
- CoffeeScriptのあまり知られていない文法 - mizch log
- あまり知られていない文法の解説です、有難いです。
- gulp & browserify
- タスクランナーgulp.js最速入門 - id:anatooのブログ
- 打倒Grunt!Node.js用の新たなビルドシステムgulpことはじめ - OpenWeb
- 両サイトとも最初の一歩を手取り足取りで教えてくれます。
- Browserify: それはrequire()を使うための魔法の杖 - cognitom Qiita
- gulpでbrowserify使ってcoffee-scriptの監視とコンパイル - mizch Qiita
- browserifyを使ったJSファイルたちの結合を、gulpを使って簡単に実行する方法が紹介されています。
Dashが鬼神のごとく便利
紹介記事にすすめられるがままにインストールしていたDash。
いままで自分が設定したショートカットすら忘れるほどの頻度でしか使ってなかったのですが、新しい言語やフレームワークを使いはじめると必然的にリファレンスを読む機会が多くなります。そして、オフラインでいつでリファレンスが読めるのはやはりすばらしいです。
現在使ってなくても興味あるフレームワークはドキュメントをダウンロードしてあります。
試したいもの
JSテストフレームワーク
やらねば、と思いつつまだ触ってないものシリーズのうちのひとつです。
casper、mocha、jasmineのいずれかをまずは試してみます。
Jenkins、Travis CI
まず何をするものなのかがとても漠然としている状態、おじさんのイラスト。
Sass || Less || Stylus && Haml || Emmet || Jade
このへんもまだ手を付けていないんです、というかどれを使えばいいんだろ。
まずはなんでもいいから一個やってみるか。
LiveScript
CoffeeScriptを調べてた流れで当然出てくるわけです、でもまだこれは自分には早いようなきがしなくもない。
Swift
文法とかの解説記事をちょいちょい見ている、早く触ってみたいけどディベロッパープログラムに入ってないからまだ無理。
Yosemite出たらやってみよう。