在 Java 中使用列表列表

Posted

技术标签:

【中文标题】在 Java 中使用列表列表【英文标题】:Working with a List of Lists in Java 【发布时间】:2010-12-01 06:57:53 【问题描述】:

我正在尝试将 CSV 文件读入(字符串)列表列表,将其传递以从数据库中获取一些数据,构建新数据列表的新列表,然后传递该列表列表,以便可以将其写入新的 CSV 文件。 我已经查看了所有内容,但似乎找不到有关如何执行此操作的示例

我宁愿不使用简单的数组,因为文件的大小会有所不同,而且我不知道数组的维度应该使用什么。我处理文件没有问题。我只是不确定如何处理列表列表。

我发现的大多数示例都将创建多维数组或在从文件中读取数据的循环内执行操作。我知道我可以做到,但我想编写面向对象的代码。如果您能提供一些示例代码或指向我的参考,那就太好了。

【问题讨论】:

【参考方案1】:
ArrayList<ArrayList<String>> listOLists = new ArrayList<ArrayList<String>>();
ArrayList<String> singleList = new ArrayList<String>();
singleList.add("hello");
singleList.add("world");
listOLists.add(singleList);

ArrayList<String> anotherList = new ArrayList<String>();
anotherList.add("this is another list");
listOLists.add(anotherList);

【讨论】:

【参考方案2】:

以下示例将 CSV 字符串列表读取到列表列表中,然后循环遍历该列表列表并将 CSV 字符串打印回控制台。

import java.util.ArrayList;
import java.util.List;

public class ListExample

    public static void main(final String[] args)
    
        //sample CSV strings...pretend they came from a file
        String[] csvStrings = new String[] 
                "abc,def,ghi,jkl,mno",
                "pqr,stu,vwx,yz",
                "123,345,678,90"
        ;

        List<List<String>> csvList = new ArrayList<List<String>>();

        //pretend you're looping through lines in a file here
        for(String line : csvStrings)
        
            String[] linePieces = line.split(",");
            List<String> csvPieces = new ArrayList<String>(linePieces.length);
            for(String piece : linePieces)
            
                csvPieces.add(piece);
            
            csvList.add(csvPieces);
        

        //write the CSV back out to the console
        for(List<String> csv : csvList)
        
            //dumb logic to place the commas correctly
            if(!csv.isEmpty())
            
                System.out.print(csv.get(0));
                for(int i=1; i < csv.size(); i++)
                
                    System.out.print("," + csv.get(i));
                
            
            System.out.print("\n");
        
    

我认为非常简单。只需注意几点:

    我建议在创建列表对象时在左侧使用“List”而不是“ArrayList”。最好传递接口“List”,因为如果以后您需要更改为使用 Vector 之类的东西(例如,您现在需要同步列表),您只需使用“new”语句更改行。无论您使用哪种列表实现,例如Vector 或 ArrayList,你仍然总是只是传递List&lt;String&gt;

    在 ArrayList 构造函数中,您可以将列表留空,它将默认为一定大小,然后根据需要动态增长。但是,如果您知道您的列表可能有多大,您有时可以节省一些性能。例如,如果您知道文件中总是有 500 行,那么您可以这样做:

List&lt;List&lt;String&gt;&gt; csvList = new ArrayList&lt;List&lt;String&gt;&gt;(500);

这样您就不会浪费处理时间等待您的列表动态增长。这就是我将“linePieces.length”传递给构造函数的原因。通常没什么大不了的,但有时很有帮助。

希望有帮助!

【讨论】:

您的示例虽然相当详细,但也颇具误导性。逐行读取CSV文件并以逗号分隔行而不考虑周围的引号是自找麻烦。 我同意你和其他所有人的观点,即 CSV 并不像用逗号分割那么简单。我的印象是问题的关键是演示如何使用泛型和列表列表,而不是解析 CSV。我喜欢 OpenCSV 作为一个包,所以我绝对同意你和其他所有人的观点,并推荐类似的东西来实际解析行。感谢您的反馈! List&lt;List&lt;String&gt;&gt; csvList = new ArrayList&lt;List&lt;String&gt;&gt;(500) 不要创建固定列表。【参考方案3】:

如果您真的很想知道用 Java 完美处理 CSV 文件,那么尝试自己实现 CSV 读取器/写入器并不好。看看下面。

http://opencsv.sourceforge.net/

当您的 CSV 文档包含双引号或换行符时,您将面临困难。

首先要学习面向对象的方法,查看其他实现(通过 Java)将对您有所帮助。而且我认为这不是管理列表中的一行的好方法。 CSV 不允许您有不同的列大小。

【讨论】:

+1 建议使用 OpenCSV。但是,尝试自己实现 CSV 读取器/写入器很好,尤其是对于 java 新手来说 - 你会在此过程中学到很多东西。【参考方案4】:

@tster 提供的示例展示了如何创建列表列表。我将提供一个迭代此类列表的示例。

Iterator<List<String>> iter = listOlist.iterator();
while(iter.hasNext())
    Iterator<String> siter = iter.next().iterator();
    while(siter.hasNext())
         String s = siter.next();
         System.out.println(s);
     

【讨论】:

【参考方案5】:

这样的东西适合阅读:

String filename = "something.csv";
BufferedReader input = null;
List<List<String>> csvData = new ArrayList<List<String>>();
try 

    input =  new BufferedReader(new FileReader(filename));
    String line = null;
    while (( line = input.readLine()) != null)
    
        String[] data = line.split(",");
        csvData.add(Arrays.toList(data));
    

catch (Exception ex)

      ex.printStackTrace();

finally 

    if(input != null)
    
        input.close();
    

【讨论】:

【参考方案6】:

我赞同 xrath 所说的 - 你最好使用现有的库来处理读取/写入 CSV。

如果您确实计划推出自己的框架,我还建议不要使用 List&lt;List&lt;String&gt;&gt; 作为您的实现 - 您最好实现 CSVDocumentCSVRow 类(可能在内部使用 @ 987654324@ 或 List&lt;String&gt; ),虽然对于用户来说,只公开一个不可变的列表或数组。

简单地使用List&lt;List&lt;String&gt;&gt; 会留下太多未经检查的边缘情况并依赖于实现细节 - 例如,标头是否与数据分开存储?还是他们在List&lt;List&lt;String&gt;&gt; 的第一行?如果我想从行中按列标题而不是按索引访问数据怎么办?

当你调用类似的东西时会发生什么:

// reads CSV data, 5 rows, 5 columns 
List<List<String>> csvData = readCSVData(); 
csvData.get(1).add("extraDataAfterColumn"); 
// now row 1 has a value in (nonexistant) column 6
csvData.get(2).remove(3); 
// values in columns 4 and 5 moved to columns 3 and 4, 
// attempting to access column 5 now throws an IndexOutOfBoundsException.

您可以在写出 CSV 文件时尝试验证所有这些,这在某些情况下可能会起作用...但在其他情况下,您会提醒用户远离错误更改的地方发生异常,导致调试困难。

【讨论】:

【参考方案7】:
 public class TEst 

    public static void main(String[] args) 

        List<Integer> ls=new ArrayList<>();
        ls.add(1);
        ls.add(2);
        List<Integer> ls1=new ArrayList<>();
        ls1.add(3);
        ls1.add(4);
        List<List<Integer>> ls2=new ArrayList<>();
        ls2.add(ls);
        ls2.add(ls1);

        List<List<List<Integer>>> ls3=new ArrayList<>();
        ls3.add(ls2);


        methodRecursion(ls3);
    

    private static void methodRecursion(List ls3) 
        for(Object ls4:ls3)
        
             if(ls4 instanceof List)    
             
                methodRecursion((List)ls4);
             else 
                 System.out.print(ls4);
             

        
    


【讨论】:

虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 递归用于嵌套列表的检索【参考方案8】:

这也是如何使用高级 for 循环打印列表列表的示例:

public static void main(String[] args)
        int[] a=1,3, 7, 8, 3, 9, 2, 4, 10;
        List<List<Integer>> triplets;
        triplets=sumOfThreeNaive(a, 13);
        for (List<Integer> list : triplets)
            for (int triplet: list)
                System.out.print(triplet+" ");
            
            System.out.println();
        
    

【讨论】:

以上是关于在 Java 中使用列表列表的主要内容,如果未能解决你的问题,请参考以下文章

在spark java中使用isin函数时保持列表的顺序

如何收集清单 列表 在java中使用流?

如何在 Java 中使用泛型转换列表?

使用 Java 8 在数组/列表中收集文件名 [重复]

如何使用自定义模型在java中获取列表索引

使用java 8迭代和过滤两个列表