[140805] cbrt直しました。あとPy3の不具合修正。
全て無限リストです。
鍋谷さんからDRYになっていないという指摘を受けたので、リファクタリングしました。
Githubのコミットログ。
https://github.com/cielavenir/procon/commit/752122c53288d8428dc4aadfbdfae7eac151eea2
なんと平均25行の削減に成功しました。
ところでGoとC#には関数の部分適用を行うメソッドってないんですかね?
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#
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を用意すると直接実行できるようです。
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)
と書けます。
- f[e]の値がProcなので
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
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