Skip to content

Instantly share code, notes, and snippets.

@fumokmm
Created June 12, 2012 21:56
Show Gist options
  • Save fumokmm/2920371 to your computer and use it in GitHub Desktop.
Save fumokmm/2920371 to your computer and use it in GitHub Desktop.
"先頭からn個のfizzになる数を取得する"をGroovyで遅延リストな感じで
/**
* 遅延リスト
*
* filter フィルタ処理
* map マップ処理
* はtakeするまで遅延されます。
*/
class LazyList {
/** 遅延リストの有効化 */
static def load() {
def filterClos = { Closure clos ->
new LazyList(iter: delegate.iterator()).filter(clos)
}
def mapClos = { Closure clos ->
new LazyList(iter: delegate.iterator()).map(clos)
}
List.metaClass.filter = filterClos
List.metaClass.map = mapClos
InfinityIntList.metaClass.filter = filterClos
InfinityIntList.metaClass.map = mapClos
}
def iter
static enum OPE_TYPE { filter, map }
def operators = []
/** フィルタ処理 */
def filter(Closure clos) {
operators << [type: OPE_TYPE.filter,
ope : clos]
this
}
/** マップ処理 */
def map(Closure clos) {
operators << [type: OPE_TYPE.map,
ope : clos]
this
}
/** 取得処理 */
def take(int num) {
def result = []
while (iter.hasNext() && result.size() < num) {
def item = iter.next()
for (o in operators) {
if (o.type == OPE_TYPE.filter) {
if (! o.ope(item)) {
item = false
break
}
} else if (o.type == OPE_TYPE.map) {
item = o.ope(item)
}
}
if (item) result << item
}
result
}
}
/**
* 無限整数リスト
*
* 開始から無限の整数リストを構築します。
* 開始を省略した場合、0からとなります。
*
* 例: "1〜" の無限整数リスト
* new InfinityIntList(start: 1)
*/
class InfinityIntList implements Iterable {
int start = 0
Iterator iterator() {
[hasNext: {true}, next: {this.start++}] as Iterator
}
}
// ここからメイン
LazyList.load()
// 上:リストに対して処理
// 下:無限整数リストに対して処理
// は同じ結果となる
assert (1..100).toList().filter{ it % 3 == 0 }.map{ "$it:Fizz" }.take(5) ==
new InfinityIntList(start: 1).filter{ it % 3 == 0 }.map{ "$it:Fizz" }.take(5)
// 結果 => [3:fizz, 6:fizz, 9:fizz, 12:fizz, 15:fizz]
// Step 1. 1〜の無限リストを生成
new InfinityIntList(start: 1).map{
// Step 2. FizzBuzzにマップ => 結果例 [num:1, label:''], [num:2, label:''], [num:3, label:'Fizz'], ...
switch(['isFizz?': it % 3 == 0, 'isBuzz?': it % 5 == 0]) {
case {it.'isFizz?' && it.'isBuzz?'} : return [num: it, label: 'FizzBuzz']
case {it.'isFizz?'} : return [num: it, label: 'Fizz' ]
case {it.'isBuzz?'} : return [num: it, label: 'Buzz' ]
default : return [num: it, label: '' ]
}
}.filter{
// Step 3. Fizz のみに絞り込み
it.label == 'Fizz'
}.map {
// Step 4. num を抽出
it.num
}
// Step 5. 5つ取得
.take(5)
// 結果 => [3, 6, 9, 12, 18]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment