ラベル Julia の投稿を表示しています。 すべての投稿を表示
ラベル Julia の投稿を表示しています。 すべての投稿を表示

2020年8月22日土曜日

NimでZipファイルにしたテキストを読む

nimというプログラミング言語を試してみた。 pythonのように書けるけど、静的な型付けのコンパイラなので、 実行速度のパフォーマンスがよいということである。

大きなカンマ区切りの値(CSV)やタブ区切りの値(TSV)といった テキストデータをzipで圧縮するとだいぶ小さくなるので、 そのようにして保存しておくことも多い。 そのようなテキストファイルを読み込みたいときに、 zipファイルを扱うモジュールが利用できると便利である。

そこで、datafile.txtというテキストファイルをzip圧縮した、 datafile.zipを読み込んで、各行をプリントするだけというスクリプトを書いてみた。

Python(v3.83 windows 64bit)では、以下のようなスクリプトになる。

import io
import zipfile

def readzip():
    filename = "datafile.zip"
    try:
        z = zipfile.ZipFile(filename, 'r')
    except:
        print("Opening zip failed")
        exit(-1)
    try:
        for fname in z.namelist():
            print(fname)
            fp = io.TextIOWrapper(z.open(fname, 'r'))
            line = fp.readline().strip()
            while line:
                print(line)
                line = fp.readline().strip()
            fp.close()
    finally:
        z.close()

if __name__ == '__main__':
    readzip()       
nimでは、zipパッケージにあるzipfilesモジュールを利用する。
import streams
import zip\zipfiles

proc readzip() =
    var filename = "datafile.zip"
    var z: ZipArchive
    var line = ""
    if not z.open(filename):
        echo "Opening zip failed"
        quit(1)
    try:
        for f in walkFiles(z):
            echo f
            var fs = z.getStream(f)
            while fs.readLine(line):
                echo line
            fs.close()
    finally:
        z.close()

when isMainModule:
    readzip()
コンパイルは、readzip.nimというファイルに書いたとすると、
nim c readzip.nim
でできるが、その前にzipパッケージをインストールする必要がある。 Gitがインストールされていれば、
nimble install zip
でインストールできる。 さらに、Windowsでコンパイルすると、gccでコンパイルされるときに エラーで止まってしまった。 こちらにあるように、修正するとコンパイルできた。

ついでなので、Julia(v1.5 windows 64-bit)でも書いてみた。 juliaでは、ZipFile.jlが利用できる。

using Pkg
Pkg.add("ZipFile")
としてインストールできた。
using ZipFile

function readzip()
    filename = "datafile.zip"
    local z

    try
        z = ZipFile.Reader(filename)
    catch
        println("Opening zip failed")
        exit(-1)
    end

    try
        for f in z.files
            println(f.name)

            while !eof(f)
                line = readline(f)
                println(line)
            end
        end
    finally
        close(z)
    end
end

readzip()       
Juliaでは、tryブロックもスコープを作るようで、tryブロック内で作った変数zを、 そのtryブロックから出た後でも利用するために、local z宣言をしている。

どれも似たような感じに書けたが、Juliaは、関数が充実しているからかシンプルに感じる。 whileのループは、eachline(f)を用いたforループで書くと、すっきりする。

2016年11月18日金曜日

一文字飛ばしにした文字列へ変換する

ある文字列を一文字飛ばしにした文字列へ変換する関数をRubyで書くという話を見かけました。 "abcdefg"を入力したら"aceg"が帰ってくる関数です。 Pythonを使っていると、関数を書くまでもなくs[::2]としたら望みの文字列が得られます。せっかくだからRubyで書いてみました。
pythonでは、
def one_skipped(s):
    return s[::2]

print one_skipped('abcdefg') #=> 'aceg'

と関数にするまでもありません。 Juliaでも、
function one_skipped(s)
    s[1:2:length(s)]
end

print(one_skipped("abcdefg"))

のように文字列から文字列を生成できます。

Rubyでも文字列のメソッドに便利なものがあるのかと見てみましたが、 slice()では、範囲のみの指定のようです。 インデックスを指定して一文字取り出すことはできるようですので、 一つとびのインデックスさえ生成できれば、それをもとに文字列を組み立てられそうです。
def one_skipped(s)
    return (0..s.length/2).map {|i| i*2}.collect {|i| s[i]}.join()
end

Rubyはreturnを省略できるということ。i*2として一つ飛びの数に直すより、 i%2==0の判定を使って取り出したいということで、selectメソッドを使ってみます。
def one_skipped(s)
    (0..s.length).select {|i| i%2==0}.collect {|i| s[i]}.join()
end
ずらずらと記述が並びますね。関数に分けてみます。

def range(start, stop, step)
    (start .. stop).select {|i| (i-start)%step==0}
end

def chars_at_indices(s, indices)
    indices.collect {|i| s[i]}
end

def one_skipped(s)
    chars_at_indices(s, range(0, s.length, 2)).join()
end

puts 'abcdefg'
こんな感じでしょうか。関数に分けるほどでもないでしょうか。 せっかく関数に分けたので、SBCLでも書いてみます。
(defun range (start stop step)
  (loop for i from start below stop by step collect i))

(defun chars-at-indices (s indices)
  (loop for i in indices collect (elt s i)))

(defun one-skipped (s)
  (concatenate 'string (chars-at-indices s (range 0 (length s) 2))))

普段使わない言語を、ちょっと調べつつ書いてみる題材としてちょうどよいですね。

Rubyは、Windows上で、
ruby 2.1.2p95 (2014-05-08 revision 45877)
irb 0.9.6(09/06/30)
を用いました。