在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毫秒),我也尝试了一些较大的数据集。我喜欢你答案的最后一部分,虽然它说没有必要过早优化,因为它们是万恶之源。