多段階選抜 (Go/C#/Ruby/Python)


|多段階選抜|解答日|シリーズ:yieldの練習/ジェネレータを入れ子に/整数平方根・立方根の実装|
|:--|:--|:--|
|問題|　|http://nabetani.sakura.ne.jp/hena/ord24eliseq/<br>https://qiita.com/Nabetani/items/1c83005a854d2c6cbb69|
|Ruby|2014/8/2(当日)|https://qiita.com/cielavenir/items/9f15e29b73ecf98968a5|
|C#/Python|2014/8/4|https://qiita.com/cielavenir/items/a1156e6a4f71ddbe5dcb|
| |　|ここから上はdrop_prev_square/drop_prev_cubicをまとめる前の答案|
|Go/C#/Ruby/Python|2014/8/5|https://qiita.com/cielavenir/items/2a685d3080862f2c2c47|
|PHP/JavaScript|2014/9/9|https://qiita.com/cielavenir/items/28d613ac3823afbf8407|
|VB|2014/9/10|https://qiita.com/cielavenir/items/cb7266abd30eadd71c04|
|D|2015/12/21|https://qiita.com/cielavenir/items/47c9e50ee60bef2847ec|
|Perl|2017/3/10|https://qiita.com/cielavenir/items/6dfbff749d833c0fd423|
|Lua|2017/3/13|https://qiita.com/cielavenir/items/c60fe7e8da73487ba062|
|C++20(TS)|2017/3/15|https://qiita.com/cielavenir/items/e1129ca185008f49cbab (MSVC)<br>https://qiita.com/cielavenir/items/1cfa90d73d11bb7dc3d4 (clang)|
|F#|2017/3/17|https://qiita.com/cielavenir/items/a698d6a26824ff53de81|
|Boo/Nemerle|2017/5/13|https://qiita.com/cielavenir/items/e2a783f0fe4b0fe0ed48|
|Perl6|2017/5/15|https://qiita.com/cielavenir/items/656ea17fa96c865c4498|
|Kotlin|2017/5/25|https://qiita.com/cielavenir/items/9c46ce8d9d12e51de285|
|Crystal|2018/5/8|https://qiita.com/cielavenir/items/1815bfa6a860fd1f90db|
|MoonScript|2018/6/16|https://qiita.com/cielavenir/items/8b03cce0386f4537b5ad|
|Julia/Rust|2018/12/20|https://qiita.com/cielavenir/items/3ddf72b06d625da0c4a5|
|Nim|2018/12/26|https://qiita.com/cielavenir/items/5728944867e609fd52a7|
|Tcl|2018/12/31|https://qiita.com/cielavenir/items/76cbd9c2022b48c9a2c9|
|Pascal/Cobra|2019/1/16|https://qiita.com/cielavenir/items/81b81baf8dfc1f877903|
|Icon|2019/1/17|https://qiita.com/cielavenir/items/889622dcc721f5a4da24|
|Swift|2020/5/31|https://qiita.com/cielavenir/items/3b0b84a218e35d538f7f|
|Java/Groovy/Scala|2020/5/31|https://qiita.com/cielavenir/items/7f058203a8fd03b65870|
|V|2020/10/17|https://qiita.com/cielavenir/items/df30a6c101a97a713df5|
|Zig/Zen|2020/10/17|https://qiita.com/cielavenir/items/9cced9e4a94dcd70df0f|
|Pike|2020/11/2|https://qiita.com/cielavenir/items/3a8248f41611302b34fd|
|Vala/Smalltalk|2020/11/29|https://qiita.com/cielavenir/items/085dabe593cd916af5e8|
|Objective-C|2020/11/30|https://qiita.com/cielavenir/items/a1736e38789a3dd5cc5a|
|Ruby(Ractor)|2021/1/2|https://qiita.com/cielavenir/items/f493c6d512b63cc571cc|
|Python(_xxsubinterpreters)|2021/6/29|https://qiita.com/cielavenir/items/f1f581a055db918954f1|
|Falcon/Scheme|2021/9/5|https://qiita.com/cielavenir/items/c13d12cf44f0d17f4a94|
|Clojure/Lisp|2021/9/7|https://qiita.com/cielavenir/items/7458ba076f4e5bc0f196|
|(icbrtの実装に関する)補題|2017/5/11|整数除算であってもn/(x*y)はn/x/yに等しい(ことの証明)<br>https://qiita.com/cielavenir/items/21a6711afd6be8c18c55|

[140805] cbrt直しました。あとPy3の不具合修正。

全て無限リストです。
鍋谷さんからDRYになっていないという指摘を受けたので、リファクタリングしました。

Githubのコミットログ。
https://github.com/cielavenir/procon/commit/752122c53288d8428dc4aadfbdfae7eac151eea2
なんと平均25行の削減に成功しました。

ところでGoとC#には関数の部分適用を行うメソッドってないんですかね？

## Go
ジェネリクス使わないとこれほどまでに楽になるとは。

```go:hena24_enum.go
//usr/bin/env go run $0 $@;exit

// http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
// http://nabetani.sakura.ne.jp/hena/ord24eliseq/

package main
import (
	"fmt"
	//"math"
	"bufio"
	"os"
)

func isqrt(n int) int{
	if n<=0 {return 0}
	if n<4 {return 1}
	x:=0
	y:=n
	for x!=y&&x+1!=y {x=y;y=(n/y+y)/2}
	return x
}
func icbrt(n int) int{
	if n<0 {return -icbrt(-n)}
	if n==0 {return 0}
	if n<8 {return 1}
	x:=0
	y:=n
	for x!=y&&x+1!=y {x=y;y=(n/y/y+y*2)/3}
	return x
}

func is_sq(n int) bool{
	//x:=int(math.Sqrt(float64(n)))
	x:=isqrt(n)
	return x*x==n
}
func is_cb(n int) bool{
	//x:=int(math.Cbrt(float64(n)))
	x:=icbrt(n)
	return x*x*x==n
}
func is_multiple(i int,n int) bool{ return i%n==0 }
func is_le(i int,n int) bool{ return i<=n }

func generate() <-chan int{
	ch := make(chan int)
	go func(){
		i:=1
		for {
			ch <- i
			i++
		}
	}()
	return ch
}

func drop_prev(check func(int)bool,prev <-chan int) <-chan int{
	ch := make(chan int)
	go func(){
		a:=<-prev
		b:=<-prev
		for {
			if !check(b) { ch<-a }
			a=b
			b=<-prev
		}
	}()
	return ch
}

func drop_next(check func(int)bool,prev <-chan int) <-chan int{
	ch := make(chan int)
	go func(){
		a:=<-prev
		b:=<-prev
		ch<-a
		for {
			if !check(a) { ch<-b }
			a=b
			b=<-prev
		}
	}()
	return ch
}

func drop_n(check func(int,int)bool,n int,prev <-chan int) <-chan int{
	ch := make(chan int)
	go func(){
		i:=0
		for {
			i++
			a:=<-prev
			if !check(i,n) { ch<-a }
		}
	}()
	return ch
}

func main(){
	f:=map[int]func(<-chan int)<-chan int{
		'S': func(prev <-chan int)<-chan int{return drop_next(is_sq,prev)},
		's': func(prev <-chan int)<-chan int{return drop_prev(is_sq,prev)},
		'C': func(prev <-chan int)<-chan int{return drop_next(is_cb,prev)},
		'c': func(prev <-chan int)<-chan int{return drop_prev(is_cb,prev)},
		'h': func(prev <-chan int)<-chan int{return drop_n(is_le,100,prev)},
	}
	for i:=2;i<10;i++ {
		j:=i //寿命が短いスコープを作ることで、ラムダ式のキャプチャでバグらないようにする。
		f[j+'0']=func(prev <-chan int)<-chan int{return drop_n(is_multiple,j,prev)}
	}

	sin:=bufio.NewReader(os.Stdin)
	_line,_,_:=sin.ReadLine()
	line:=string(_line)
	for line!="" {
		//cS => f['S'](f['c'](generate()))
		ch := generate()
		for _,c:=range(line) {
			ch=f[int(c)](ch)
		}
		for i:=0;i<10;i++ {
			if i>0 { fmt.Print(",") }
			a:=<-ch
			fmt.Printf("%d",a)
		}
		fmt.Println()
		os.Stdout.Sync()
		_line,_,_=sin.ReadLine()
		line=string(_line)
	}
}
```

## C# ##

```csharp:hena24_enum.cs
// http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
// http://nabetani.sakura.ne.jp/hena/ord24eliseq/

using System;
using System.Linq;
using System.Collections.Generic;
//using System.Runtime.InteropServices;

class Hena24{
	//[DllImport("c")]
	//private extern static double cbrt(double d);

	static private int isqrt(int n){
		if(n<=0)return 0;
		if(n<4)return 1;
		int x=0,y=n;
		for(;x!=y&&x+1!=y;){x=y;y=(n/y+y)/2;}
		return x;
	}
	static private int icbrt(int n){
		if(n<0)return -icbrt(-n);
		if(n==0)return 0;
		if(n<8)return 1;
		int x=0,y=n;
		for(;x!=y&&x+1!=y;){x=y;y=(n/y/y+y*2)/3;}
		return x;
	}

	static private bool is_sq(int n){
		//int x=(int)Math.Sqrt(n);
		int x=isqrt(n);
		return x*x==n;
	}
	static private bool is_cb(int n){
		//int x=(int)cbrt(n);
		int x=icbrt(n);
		return x*x*x==n;
	}
	static private bool is_multiple(int i,int n){return i%n==0;}
	static private bool is_le(int i,int n){return i<=n;}

	static private IEnumerable<int> generate(){
		int i=1;
		for(;;){
			yield return i;
			i+=1;
		}
	}
	static private IEnumerable<int> drop_prev(
		Func<int,bool> check,IEnumerable<int> _prev
	){
		IEnumerator<int> prev=_prev.GetEnumerator();
		prev.MoveNext();
		int a=prev.Current;
		prev.MoveNext();
		int b=prev.Current;
		for(;;){
			if(!check(b))yield return a;
			a=b;
			prev.MoveNext();
			b=prev.Current;
		}
	}
	static private IEnumerable<int> drop_next(
		Func<int,bool> check,IEnumerable<int> _prev
	){
		IEnumerator<int> prev=_prev.GetEnumerator();
		prev.MoveNext();
		int a=prev.Current;
		prev.MoveNext();
		int b=prev.Current;
		yield return a;
		for(;;){
			if(!check(a))yield return b;
			a=b;
			prev.MoveNext();
			b=prev.Current;
		}
	}
	static private IEnumerable<int> drop_n(
		Func<int,int,bool> check,int n,IEnumerable<int> _prev
	){
		IEnumerator<int> prev=_prev.GetEnumerator();
		int i=0;
		for(;;){
			i++;
			prev.MoveNext();
			int a=prev.Current;
			if(!check(i,n))yield return a;
		}
	}
	static public void Main(){
		var f=new Dictionary<char,Func<IEnumerable<int>,IEnumerable<int>>>(){
			{'S',e => drop_next(is_sq,e)},
			{'s',e => drop_prev(is_sq,e)},
			{'C',e => drop_next(is_cb,e)},
			{'c',e => drop_prev(is_cb,e)},
			{'h',e => drop_n(is_le,100,e)},
		};
		for(int i=2;i<10;i++){
			int j=i; //寿命が短いスコープを作ることで、ラムダ式のキャプチャでバグらないようにする。
			f[(char)('0'+j)] = e=>drop_n(is_multiple,j,e);
		}
		string line;
		for(;(line=Console.ReadLine())!=null;){
			bool first=true;
			//cS => f['S'](f['c'](generate()))
			foreach(int n in line.Aggregate(generate(),(s,e)=>f[e](s)).Take(10)){
				if(!first)Console.Write(',');
				first=false;
				Console.Write(n);
			}
			Console.WriteLine();
			Console.Out.Flush();
		}
	}
}
```

### 実行可能

このようなcsxを用意すると直接実行できるようです。

```csharp:tyama_hena24_enum.csx
//usr/bin/env csi $0 $@;exit

#load "tyama_hena24_enum.cs"
Hena24.Main()
```

## Ruby

- 220202: 本当に今更なんですが、`f[e].call(s)`は、
    - f[e]の値がProcなので`f[e][s]`と書けます。
    - Ruby 1.9以上だと`f[e].(s)`と書けます。

```rb:hena24_enum.rb
#!/usr/bin/env ruby
#http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
#http://nabetani.sakura.ne.jp/hena/ord24eliseq/

=begin
if RUBY_VERSION<'1.9'
	module Math
		def self.cbrt(n)
			n**(1-2.0/3)
		end
	end
end
=end

class Integer
	def isqrt
		return 0 if self<=0
		return 1 if self<4 # 1
		x,y=0,self
		while x!=y&&x+1!=y
			x,y=y,(self/y+y)/2
		end
		x
	end
	def icbrt
		return -(-self).icbrt if self<0
		return 0 if self==0
		return 1 if self<8 # 1,7
		x,y=0,self
		while x!=y&&x+1!=y
			x,y=y,(self/y/y+y*2)/3
		end
		x
	end
end

=begin
def generate
	return to_enum(:generate) if !block_given?
	i=1
	loop{
		yield i
		i+=1
	}
end
=end

def drop_prev(check,prev)
	return to_enum(:drop_prev,check,prev) if !block_given?
	a=prev.next
	b=prev.next
	loop{
		yield a if !check[b]
		a,b=b,prev.next
	}
end
def drop_next(check,prev)
	return to_enum(:drop_next,check,prev) if !block_given?
	a=prev.next
	b=prev.next
	yield a
	loop{
		yield b if !check[a]
		a,b=b,prev.next
	}
end
def drop_n(check,n,prev)
	return to_enum(:drop_n,check,n,prev) if !block_given?
	i=0
	loop{
		i+=1
		a=prev.next
		yield a if !check[i,n]
	}
end

is_sq=lambda{|n|n.isqrt**2==n}
is_cb=lambda{|n|n.icbrt**3==n}
is_multiple=lambda{|i,n|i%n==0}
is_le=lambda{|i,n|i<=n}

if RUBY_VERSION<'1.9'
	f={
		'S'=>lambda{|enum|drop_next(is_sq,enum)},
		's'=>lambda{|enum|drop_prev(is_sq,enum)},
		'C'=>lambda{|enum|drop_next(is_cb,enum)},
		'c'=>lambda{|enum|drop_prev(is_cb,enum)},
		'h'=>lambda{|enum|drop_n(is_le,100,enum)},
	}
	(2..9).each{|e|f[e.to_s]=lambda{|enum|drop_n(is_multiple,e,enum)}}
else
	f={
		'S'=>Kernel.method(:drop_next).to_proc.curry[is_sq],
		's'=>Kernel.method(:drop_prev).to_proc.curry[is_sq],
		'C'=>Kernel.method(:drop_next).to_proc.curry[is_cb],
		'c'=>Kernel.method(:drop_prev).to_proc.curry[is_cb],
		'h'=>Kernel.method(:drop_n).to_proc.curry[is_le,100],
	}
	(2..9).each{|e|f[e.to_s]=Kernel.method(:drop_n).to_proc.curry[is_multiple,e]}
end

if $0==__FILE__
	STDOUT.sync=true
	while gets
		#cS => f['S'].call(f['c'].call(1.upto(1/0.0)))
		puts $_.chomp.chars.reduce(1.upto(1/0.0)){|s,e|f[e][s]}.take(10)*','

		#enum=generate
		#$_.chomp.chars.each{|e|enum=f[e][enum]}
		#puts enum.take(10)*','
	end
end
```

## Python

```py:hena24_enum.py
#!/usr/bin/env python
#http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
#http://nabetani.sakura.ne.jp/hena/ord24eliseq/
import sys
import itertools
from functools import partial,reduce

'''
from math import sqrt
try:
	#from scipy.special import cbrt # thx @ryosy383
    from numpy import cbrt
except ImportError:
	try:
		import ctypes
		if sys.platform.startswith('linux'):
			libm=ctypes.cdll.LoadLibrary('libm.so.6')
		elif sys.platform=='darwin':
			libm=ctypes.cdll.LoadLibrary('libSystem.dylib')
		elif sys.platform=='win32':
			libm=ctypes.cdll.LoadLibrary('msvcr120.dll')
		else:
			raise ImportError
		cbrt=lambda n:libm.cbrt(ctypes.c_double(n))
		libm.cbrt.restype=ctypes.c_double
	except ImportError:
		cbrt=lambda n: n**(1-2.0/3)
'''

def isqrt(n):
	if n<=0: return 0
	if n<4: return 1
	x,y=0,n
	while x!=y and x+1!=y:
		x,y=y,(n//y+y)//2
	return x
def icbrt(n):
	if n<0: return -icbrt(-n)
	if n==0: return 0
	if n<8: return 1
	x,y=0,n
	while x!=y and x+1!=y:
		x,y=y,(n//y//y+y*2)//3
	return x

if sys.version_info[0]>=3: raw_input=input

'''
def generate():
	i=1
	while True:
		yield i
		i+=1
'''

def drop_prev(check,prev):
	a=next(prev)
	b=next(prev)
	while True:
		if not check(b): yield a
		a,b=b,next(prev)

def drop_next(check,prev):
	a=next(prev)
	b=next(prev)
	yield a
	while True:
		if not check(a): yield b
		a,b=b,next(prev)

def drop_n(check,n,prev):
	i=0
	while True:
		i+=1
		a=next(prev)
		if not check(i,n): yield a

is_sq=lambda n: isqrt(n)**2==n
is_cb=lambda n: icbrt(n)**3==n
is_multiple=lambda i,n: i%n==0
is_le=lambda i,n: i<=n

f={
	'S': partial(drop_next,is_sq),
	's': partial(drop_prev,is_sq),
	'C': partial(drop_next,is_cb),
	'c': partial(drop_prev,is_cb),
	'h': partial(drop_n,is_le,100),
}

#cf: https://twitter.com/closureobject/status/678619154346151941
for e in range(2,10): f[str(e)]=partial(drop_n,is_multiple,e) # OK
#for e in range(2,10): f[str(e)]=lambda n:drop_n(is_multiple,e,n) #NG
#for e in range(2,10): f[str(e)]=(lambda x:lambda n:drop_n(is_multiple,x,n))(e) # OK

if __name__=='__main__':
	try:
		while True:
			#cS => f['S'](f['c'](itertools.count(1)))
			'''
			print(','.join(
				map(str,itertools.islice(
					reduce(lambda s,e:f[e](s),raw_input().rstrip(),itertools.count(1)),
				10))
			))
			'''
			g=reduce(lambda s,e:f[e](s),raw_input().rstrip(),itertools.count(1))
			print(','.join(str(next(g)) for i in range(10)))
			sys.stdout.flush()
	except EOFError:
		pass
```