LoginSignup
7
8

More than 1 year has passed since last update.

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

Last updated at Posted at 2014-08-05
多段階選抜 解答日 シリーズ:yieldの練習/ジェネレータを入れ子に/整数平方根・立方根の実装
問題   http://nabetani.sakura.ne.jp/hena/ord24eliseq/
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)
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に等しい(ことの証明)
https://qiita.com/cielavenir/items/21a6711afd6be8c18c55

[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)と書けます。
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
7
8
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8