我正在尝试将多个不同长度的数据列表输出到CSV文件。每个列表应该是输出CSV文件中的一列。有没有直接的做事方式?如果我将每个列表作为一行输出,我只是循环遍历每个列表并在结束时输出一个返回,但是这种方法在按列工作时不起作用。
我想要一次又一次地遍历所有列表,逐项并递增一个计数器,但这也会失败,因为有些列表比其他列表长。为了解决这个问题,我必须在每次迭代时检查计数器是否超过每个列表的末尾,这在计算方面相当昂贵。
感谢您的任何想法!
答案 0 :(得分:2)
值得一看http://commons.apache.org/sandbox/csv/
这也引用了一些其他CSV库。
请注意,许多答案都没有考虑包含逗号的字符串。这就是为什么图书馆比自己做的更好的原因。
答案 1 :(得分:2)
我认为这很简单:
public static void main(String... args) throws IOException {
ArrayList<ArrayList<String>> rows = getRandomData();
if (rows.size() == 0)
throw new RuntimeException("No rows");
// normalize data
int longest = 0;
for (List<String> row : rows)
if (row.size() > longest)
longest = row.size();
for (List<String> row : rows)
while (row.size() < longest)
row.add("");
if (longest == 0)
throw new RuntimeException("No colums");
// fix special characters
for (int i = 0; i < rows.size(); i++)
for (int j = 0; j < rows.get(i).size(); j++)
rows.get(i).set(j, fixSpecial(rows.get(i).get(j)));
// get the maximum size of one column
int[] maxColumn = new int[rows.get(0).size()];
for (int i = 0; i < rows.size(); i++)
for (int j = 0; j < rows.get(i).size(); j++)
if (maxColumn[j] < rows.get(i).get(j).length())
maxColumn[j] = rows.get(i).get(j).length();
// create the format string
String outFormat = "";
for (int max : maxColumn)
outFormat += "%-" + (max + 1) + "s, ";
outFormat = outFormat.substring(0, outFormat.length() - 2) + "\n";
// print the data
for (List<String> row : rows)
System.out.printf(outFormat, row.toArray());
}
private static String fixSpecial(String s) {
s = s.replaceAll("(\")", "$1$1");
if (s.contains("\n") || s.contains(",") || s.contains("\"") ||
s.trim().length() < s.length()) {
s = "\"" + s + "\"";
}
return s;
}
private static ArrayList<ArrayList<String>> getRandomData() {
ArrayList<ArrayList<String>> data = new ArrayList<ArrayList<String>>();
String[] rand = { "Do", "Re", "Song", "David", "Test", "4", "Hohjoh", "a \"h\" o", "tjo,ad" };
Random r = new Random(5);
for (int i = 0; i < 10; i++) {
ArrayList<String> row = new ArrayList<String>();
for (int j = 0; j < r.nextInt(10); j++)
row.add(rand[r.nextInt(rand.length)]);
data.add(row);
}
return data;
}
输出(非常丑陋,因为它是随机的)(escapes):
Re , 4 , "tjo,ad" , "tjo,ad" ,
"tjo,ad" , "a ""h"" o" , , ,
Re , "a ""h"" o" , Hohjoh , "tjo,ad" , 4
4 , David , , ,
4 , Test , "tjo,ad" , Hohjoh , Re
Do , Hohjoh , Test , ,
Hohjoh , Song , , ,
4 , Song , , ,
4 , Do , Song , Do ,
Song , Test , Test , ,
答案 2 :(得分:1)
创建一个迭代器数组(每个列表一个。)然后遍历数组,检查迭代器hasNext()
;如果是,输出iterator.next()
。输出逗号和换行是微不足道的。当所有迭代器都返回hasNext()==false
时停止。
答案 3 :(得分:1)
您可以使用String.format():
System.out.println(String.format("%4s,%4s,%4s", "a", "bb", "ccc"));
System.out.println(String.format("%4s,%4s,%4s", "aaa", "b", "c"));
结果将是4个字符的固定列宽 - 只要使用的值更短。否则布局会中断。
a, bb, ccc
aaa, b, c
答案 4 :(得分:1)
我根本不熟悉Java,但是如果你有一个面向matrix
的数据类型,你可以使用简单的循环填充行,然后转置它,然后使用简单的循环将其写出来。您的打印例程可以通过输出空字符串来处理空条目,或者如果您愿意,可以处理固定宽度空格。
答案 5 :(得分:0)
您可以这样做:
List<List<?>> listOfLists = new LinkedList<List<?>>();
List<Iterator<?>> listOfIterators = new LinkedList<Iterator<?>>();
for (List<?> aList : listOfLists) {
listOfIterators.add(aList.iterator());
}
boolean done = false;
while(!done)
{
done = true;
for (Iterator<?> iter : listOfIterators)
{
if (iter.hasNext())
{
Object obj = iter.next();
//PROCESS OBJ
done = false;
}
else
{
//PROCESS EMPTY ELEMENT
}
}
}
对于CSV处理,我多次使用过这个库:http://www.csvreader.com/java_csv.php非常简单方便。
Cheerz!
答案 6 :(得分:0)
我必须在每次迭代时检查计数器是否超过每个列表的末尾,这在计算方面相当昂贵。
克服它。实际上,与实际进行迭代的成本相比,这将是很小的,与将任何给定的文本位写入文件的成本相比,这反过来会很小。至少,假设你有随机访问容器。
但你不应该考虑计数器和索引;你应该考虑迭代器(避开随机访问问题并简化代码)。
答案 7 :(得分:0)
如果您想在一对循环和一种方法中执行此操作,则可以执行以下操作。
public static void writeCSV(PrintWriter pw, List<List<String>> columnsRows) {
for(int i=0;;i++) {
StringBuilder line = new StringBuilder();
boolean empty = true;
for (List<String> column : columnsRows) {
String text = i < column.size() ? column.get(i) : "";
found &= i >= column.size();
if (text.contains(",") || text.contains("\"") || text.contains("\n") || text.trim() != text)
text = '"' + text.replaceAll("\"", "\"\"") + '"';
line.append(text).append(',');
}
if (empty) break;
pw.println(line.substring(0, line.length()-1));
}
}
作为一个练习,你可以用一个循环来完成这个练习,但是它不会像它做的那样清楚。
使用来自@dacwe的样本数据,此方法需要10 us(微秒)。