我想将以下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
否?感谢
答案 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))
nil
和false
是假的,其他一切都是真实的,如果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)
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))))