在Racket中更有效地将列表写入文件
我想将一些列表(嵌套在大列表中)中的数字写入文件,例如:在Racket中更有效地将列表写入文件,racket,Racket,我想将一些列表(嵌套在大列表中)中的数字写入文件,例如: '((33 62 42 -19 30) (-22 -15 60 -55 24) (4 -48 22 -63 5)) 要在文本文件中输出,请执行以下操作: 33 62 42 -19 30 -22 -15 60 -55 24 4 -48 22 -63 5 我写了一些有用的东西,但我觉得有点慢。代码如下: #lang racket (define lists (build-list 100000 (
'((33 62 42 -19 30)
(-22 -15 60 -55 24)
(4 -48 22 -63 5))
要在文本文件中输出,请执行以下操作:
33 62 42 -19 30
-22 -15 60 -55 24
4 -48 22 -63 5
我写了一些有用的东西,但我觉得有点慢。代码如下:
#lang racket
(define lists
(build-list 100000
(λ _ (for/list ([i (in-range 5)])
(random -100 100)))))
(define (list->file lst path)
(let loop ([clone lst] [out (open-output-file path #:exists 'replace)])
(if (empty? clone)
(close-output-port out)
(begin
(for ([i (in-range (length (first clone)))])
(display (list-ref (first clone) i) out)
(when (< (+ i 1) (length (first clone))) (display " " out)))
(unless (empty? (rest clone)) (display "\n" out))
(loop (rest clone) out)))))
(time (list->file lists "test.txt"))
#朗球拍
(定义列表)
(构建列表100000)
(λu(用于/列表([i(范围5)])
(随机-100(())))
(定义(列表->文件lst路径)
(let循环([clone lst][out(打开输出文件路径#:exists'replace)])
(如果(空?克隆)
(关闭输出端口输出)
(开始
(用于([i(范围内(长度(第一个克隆)))))
(显示(列表参考(第一个克隆)i)输出)
(当(<(+I1)(长度(第一个克隆))(显示“输出”))
(除非(空?(rest克隆))(显示“\n”out))
(循环(rest克隆)输出(()()))
(时间(列表->文件列表“test.txt”))
首先,我刚刚生成了一个100000个子列表,每个子列表有5个随机数,然后在
list->file
函数中,我只为每个子列表输出每个数字,后跟一个空格,然后递归地移动到下一个子列表。有没有办法提高效率?在我的机器上,这比您的解决方案快50到100毫秒,保持完全相同的行为:
(define (print-tuple tuple out)
(cond [(empty? (rest tuple))
(display (first tuple) out)]
[else
(display (first tuple) out)
(display " " out)
(print-tuple (rest tuple) out)]))
(define (list->file lst path)
(call-with-output-file* path #:exists 'replace
(lambda (out)
(let loop ([clone lst])
(cond [(empty? (rest clone))
(print-tuple (first clone) out)]
[else
(print-tuple (first clone) out)
(newline out)
(loop (rest clone))])))))
我使用Scheme中更惯用的索引替换了访问列表中元素的代码-您应该避免使用list ref
和length
,这些操作在处理列表时非常昂贵!我还将显示逻辑提取到它自己的过程中(我们可以将它串联起来,以节省几毫秒,但这不值得)。最好对输出文件*使用调用,或者对输出到文件
使用调用,它们更简单,因为我们不需要显式关闭输出端口
我做了一些小型基准测试,发现我的代码比你的代码快,也比Sorawee的解决方案快——但一开始速度非常快,所以可能不需要过早优化,你知道它们是万恶之源。我衡量程序运行的时间。大约300米,已经非常快了。你预计需要多长时间?你为什么认为它效率低下?没有具体的目标或证据表明这是应用程序的瓶颈,这只是一个过早的优化
此外,如果性能在您的应用程序中真的很重要,那么Racket可能不是最合适的。Racket(实现)并不慢,但它的目标并不是要达到难以置信的快
无论如何,如果我要写这个程序,我会这样写:
#lang racket
(define lists
(build-list 100000
(λ _ (for/list ([i (in-range 5)])
(random -100 100)))))
(define (list->file lst path)
(with-output-to-file path #:exists 'replace
(λ ()
(for ([line (in-list lst)])
(for ([e (in-list line)] [i (in-naturals)])
(unless (zero? i) (display " "))
(display e))
(newline)))))
(time (list->file lists "test.txt"))
这个程序运行大约需要230ms,因此比您的程序快约70ms。我没有仔细测量导致差异的原因,但我想指出的是,length
和list ref
是一个线性时间操作,因此我们通常希望避免它们。但是,对于一个固定的、小尺寸(长度5)的列表,应该可以。我很好奇为什么您的程序要快得多,所以我进行了一些测量。事实证明,在我的电脑中,在Racket CS的实现中,你的电脑始终需要大约250ms的时间,这比我的慢。另一方面,在Racket BC实现中,我的需要170ms,你的需要160ms。这很奇怪,在我的计算机中,你的版本与OP的版本需要相同的时间,我假设我正在运行BC。CS和BC之间有什么区别可以解释这种差异?我不知道,但我同意这确实很奇怪。小评论:这是个人偏好的问题,但我认为在这种情况下,在索引中使用会更优雅。另外,为了准确地复制OP的输出,最后一行不应该有换行符。我们发现,我们的解决方案根据所使用的Racket版本具有完全不同的性能。要决定哪一个更“高效”,您需要在自己的环境中测试它们;)@ÓscarLópez在我的计算机上,您的解决方案是最快的(平均约100-200毫秒),我也尝试了一些较大的数据集。我喜欢你答案的最后一部分,虽然它说没有必要过早优化,因为它们是万恶之源。