我想将以下 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
不?谢谢
最佳答案
对 parquet 或您正在尝试做的事情一无所知,这是我的最佳猜测和一些观察结果:
(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
永远不会是 false 那么就使用 value
而不是 (not (nil? value))
。 (额外的陷阱:(Boolean.false)
是真实的,参见 https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L2607 :)
一定要是 vector 吗,为什么?此处的代码返回一个 seq,它由 doall 提前实现(在 with-open 范围内,相当于您的 try-finally。)
Clojure 的数据是不可变的,你不需要附加到列表,你告诉它从旧的创建一个新的并让 Clojure 处理细节:-)。一旦设置了 rows
的值,您就无法在代码示例中执行任何操作,没有“变量”。有 可变引用类型,但在这里使用它们是一种不好的形式。从技术上讲,您可以使用循环/递归来实现它,但这里没有理由这样做(可能是性能),而且通常使用惰性序列方法确实有好处。
reduce
不会工作,因为它消除了提前退出的能力,而且这里的输入是一个 java 对象,而 reduce
需要一个 seq-able 的东西,所以你仍然需要找到某种方法来生成惰性序列,而您又回到了原点。
for
不是循环,它是列表理解。它生成惰性值序列。
我不认为 new
是惯用的,我不确定为什么 :-)。不过,它是使用宏生成代码的更好选择。
花时间理解这些概念,它们在实践中非常棒!
关于java - 将 Java 翻译成 Clojure - 添加到列表并返回列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23019516/