【问题标题】:List of Lists of Lists列表列表列表
【发布时间】:2010-06-23 14:55:45
【问题描述】:

我是 Java 新手,我需要制作一个列表列表。我可以在 python 中执行此操作,因为列表的元素可以是列表,因此在嵌入式列表中list[0] 将引用一个列表,list[0][0] 将引用嵌入列表的第零个元素。有什么简单的方法可以在 java 中实现这种行为吗?

【问题讨论】:

    标签: java list


    【解决方案1】:

    所有其他答案在技术上都是正确的,但是恕我直言,如果您实现了一个粗略的 List of Lists 列表,那么您就没有在正确的抽象级别上处理您的数据。例如,我很确定 List of Lists 在您的业务领域中已经意味着“某事”。将这个“东西”封装在另一个对象中,这样您就可以只拥有一个 List 而不是难以使用和维护的 List>>。

    【讨论】:

    • 在某些语言中(诚然,不是典型的 Java,因为它的语法冗长),使用 list-of-list-of-list 在原型设计中很常见。对于探索性编程,当您没有在任何地方嵌入显式名称时,进行更改会容易得多。一旦你编写了一个企业网络应用程序,当然,你需要“正确的抽象级别”和“你的业务领域”,但是如果你正在编写一个程序来做“我还不知道什么,但让我们看看这个去”,列表很棒。 Linux 内核在开始时也不是完美的,甚至作为操作系统内核也没有。
    • 在我的工作生涯中,我无数次听到这样的理由:“我将从 List of Lists 开始,我会看看会发生什么,然后我会重构它。”在最坏的情况下,这是一个一厢情愿的想法,或者更可能只是一个谎言,其最终结果是可怕的 List of Lists 将永远保留在您的代码中。如果你已经知道有更好的方法来编写你的代码(而且你似乎同意你可以做得更好)为什么不从最好的方法开始呢?
    • 您只需花费几分钟的时间来封装...只要做到这一点,优雅!
    【解决方案2】:

    正如Mario 所说,您可能需要进一步抽象出您的数据。但是,以下将满足您的需要。

    在 Java 中你会这样:

    List<List<List<Object>>> listOfListsOfLists =new ArrayList<List<List<Object>>>();
    

    然后要访问这些项目,您将使用:

    listOfListsOfLists.get(a).get(b).get(c);
    

    或者,遍历所有内容:

    for (List<List<Object>> list2: listOfListsOfLists) {
        for (List<Object> list1: list2) {
            for (Object o: list1) {
                // use `o`
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      由于所有这些答案都让我感到恶心,我可以添加您的建议

      1. 创建一个数据类型来表达你的数据,同时封装结构的细节,或者至少

      2. 创建一个包装 int[] 的键类型(但正确覆盖 equals 和 hashCode)并使用 HashMap 代替?无论如何,您的整个 3 维结构通常很少会被填满。

      更好的是,您可以封装该映射并使用可变参数进行干净访问。

      public class NDimensionalArray<V> {
          private final int dimensions;
          private final Map<Key, V> values = new HashMap<Key, V>();
      
          private NDimensionalArray(int dimensions) {
              this.dimensions = dimensions;
          }
      
          public V get(int... indices) {
              checkIndices(indices);
              return values.get(new Key(indices));
          }
      
          public void set(V value, int... indices) {
              checkIndices(indices);
              values.put(new Key(indices), value);
          }
      
          private void checkIndices(int[] indices) {
              if ( indices.length != dimensions ) {
                  throw new IllegalArgumentException();
              }
          }
      
          private static final class Key {
              private final int[] indices;
      
              private Key(int[] indices) {
                  this.indices = indices;
              }
      
              @Override
              public int hashCode() {
                  return Arrays.hashCode(indices);
              }
      
              @Override
              public boolean equals(Object obj) {
                  return Arrays.equals(indices, ((Key)obj).indices);
              }
          }
      }
      

      如果人们有已经建立的收藏库的例子,已经做这种事情,请告诉我,我会添加链接。

      【讨论】:

      • 要么我遗漏了一些东西,要么这里有一个缺陷——数组哈希码是基于身份的,而不是基于数组中的值——你的映射键不会按预期工作?如果值范围允许非冲突 hashCode (即索引 0 .. 1000 和 hashCode = 1000000 * a[2] + 1000 * a[1] + a[ 0])
      • @rsp:谢谢,你说得对。有点太仓促了。它现在已经修复(尽管我还没有测试过)。只要正确实现了equals,哈希码就不必不冲突(毕竟,无限空间类的所有哈希码最终都会发生冲突)。
      【解决方案4】:

      虽然您可以在 Java 中构造 List>> 确实是真的,但我不禁想知道,您为什么要这样做?并不是说这是解决您的问题的最佳方法是不可思议的,但是哇,为什么?

      我想我可以想象类似的东西

      public class Employee ...
      List<Employee> store; // all the employees in a store
      List<List<Employee>> city; // all the store lists for a city
      List<List<List<Employee>>> nation; // all the store lists for the nation
      

      但是你真的想这样处理吗?我不知道,这取决于你需要用它做什么。

      【讨论】:

        【解决方案5】:

        一个全面的例子展示了 List-of-List 与集合和泛型 (Java 1.5+)

        // declare the list of lists
        List<List<String>> listOfListOfStrings = new ArrayList<List<String>>();
        
        // populate
        List<String> listOfStrings = new ArrayList<String>(); // one inner list
        listOfStrings.add("one-one");
        listOfStrings.add("one-two");
        listOfListOfStrings.add(listOfStrings);
        
        listOfStrings = new ArrayList<String>(); // and another one
        listOfStrings.add("two-one");
        listOfStrings.add("two-two");
        listOfListOfStrings.add(listOfStrings);
        
        // access
        String oneOne = listOfListOfStrings.get(0).get(0);   // first element of first inner list
        String twoTwo = listOfListOfStrings.get(1).get(1);   // second element of second inner list
        

        【讨论】:

        • 编译器“认为”add 是包listOfStrings 中的一个类(这显然是错误的)。 listOfStrings 是一个局部变量,声明就在 //populate 注释的正下方。验证您的导入语句并仔细检查代码是否在方法内。 (你有一个名为add 的类吗?)
        • 我在看到您的评论之前发现了错误。 (很抱歉删除它。)我错误地将代码放在了类上,但没有放在方法中。谢谢 Andreas_D。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-29
        • 2022-09-27
        • 2016-01-26
        • 1970-01-01
        • 2021-04-01
        • 1970-01-01
        • 2014-02-25
        相关资源
        最近更新 更多