将Java翻译为Clojure - 附加到列表和返回列表

时间:2014-04-11 17:59:15

标签: java clojure functional-programming

我想将以下java翻译成惯用的clojure:

List<SimpleRecord> recs = new ArrayList<SimpleRecord>();
ParquetReader<SimpleRecord> reader = null;
    try {
      PrintWriter writer = new PrintWriter(Main.out, true);
      reader = new ParquetReader<SimpleRecord>(new Path(input), new SimpleReadSupport());
      for (SimpleRecord value = reader.read(); value != null; value = reader.read()) {
        //value.prettyPrint(writer);
        //writer.println();
        recs.add(value);
      }
      return value;
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (Exception ex) {
        }
      }
    }

但是我无法在每一步将元素推送到列表中。 这就是我现在所拥有的:

(let [rows   (vector)
      reader (new parquet.hadoop.ParquetReader (new org.apache.hadoop.fs.Path "file.pq") 
                                               (new SimpleReadSupport))]
  ;reader  
  (try   
    (for [value (.read reader) :while (not (nil? value))]
      (conj value rows)) ;y u no recur?
    rows
    (finally (.close reader)))
  )

但我不知道在for内这样做的惯用方法是什么。我猜我必须使用reduce否?感谢

3 个答案:

答案 0 :(得分:3)

不知道任何关于实木复合地板或你想要做什么,这是我最好的猜测和一些观察:

(with-open [reader (parquet.hadoop.ParquetReader. 
                     (org.apache.hadoop.fs.Path. "file.pq") 
                     (SimpleReadSupport.))]
  (doall (for [value (repeatedly #(.read reader))
               :while value] 
           value))

nilfalse是假的,其他一切都是真实的,如果value永远不是假的,那么只需使用value而不是(not (nil? value))。 (额外的问题:(Boolean. false)是真实的,请参阅https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L2607:)

是否需要成为矢量,为什么?这里的代码返回一个seq,它由doall提前实现(在with-open范围内,相当于你的try-finally。)

Clojure的数据是不可变的,你不会附加到列表中,你告诉它从旧列表创建一个新的并让Clojure处理细节:-)。您的代码示例中没有任何内容可以在rows设置后更改reduce的值,没有'变量'。 可变引用类型,但在这里使用它们将是不好的形式。从技术上讲,你可以用loop / recur来实现它,但是这里没有理由(可能是性能),并且通常使用惰性序列方法确实有好处。

reduce不起作用,因为它消除了提前退出的能力,此处的输入也是一个java对象,而for期望一个seq-able的东西,所以你仍然需要找到某种方式来生成一个懒惰的序列,然后你回到正方形。

new不是循环,它是列表理解。它会生成一个懒惰的值序列。

我不认为{{1}}惯用,我不确定为什么:-)。不过,这是使用宏生成代码的更好选择。

花时间去理解这些概念,它们在实践中很棒!

答案 1 :(得分:2)

Clojure中的

for不是for循环,它是一个序列理解。

默认的Clojure数据结构是不可移植的,应该迭代构建,而不是在迭代中进行变异。

(with-open [reader (parquet.hadoop.ParquetReader. 
                     (org.apache.hadoop.fs.Path. "file.pq") 
                     (SimpleReadSupport.))]
  (doall
   (take-while (complement nil?)
               (repeatedly (fn []
                             (try (.read reader)
                                  (catch Exception e))))))

答案 2 :(得分:1)

gtrak的方法当然是最好的方法,但我仍然想告诉你如何在clojure中编写一个显式循环。

(with-open [reader (parquet.hadoop.ParquetReader. 
                     (org.apache.hadoop.fs.Path. "file.pq") 
                     (SimpleReadSupport.))]
  (loop [rows []]
    (let [value (.read reader)]
      (if value
          (recur (conj rows value))
          rows))))