Created
June 12, 2012 21:56
-
-
Save fumokmm/2920371 to your computer and use it in GitHub Desktop.
"先頭からn個のfizzになる数を取得する"をGroovyで遅延リストな感じで
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 遅延リスト | |
* | |
* 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