在Java中转换为面向列的数组

时间:2010-04-29 10:57:37

标签: java performance algorithm column-oriented

虽然标题中有Java,但这可能适用于任何OO语言。 我想知道一些新想法,以改善我正在尝试做的事情的表现。

我有一个不断接收Object []数组的方法。我需要通过多个数组(List或其他)拆分此数组中的Objects,以便我为该方法接收的所有数组的每一列都有一个独立的列表。

示例:

List<List<Object>> column-oriented = new ArrayList<ArrayList<Object>>();

public void newObject(Object[] obj) {
    for(int i = 0; i < obj.length; i++) {
        column-oriented.get(i).add(obj[i]);
    }
}

注意:为简单起见,我省略了对象和东西的初始化。

我上面显示的代码当然很慢。我已经尝试了一些其他的东西,但是想听听一些新的想法。

如果知道它对性能非常敏感,你会怎么做?

修改

我测试了一些东西并发现:

我没有使用ArrayList(或任何其他Collection),而是将Object []数组包装在另一个对象中以存储单个列。如果此数组达到其容量,我创建另一个具有两倍大小的数组,并使用System.copyArray将内容从一个复制到另一个。令人惊讶的是(至少对我而言)使用ArrayList存储内部列的速度更快......

4 个答案:

答案 0 :(得分:2)

答案取决于数据和使用情况。你在这些收藏中有多少数据?什么是读/写的比例(添加对象数组)?这会影响内部列表的结构更好以及许多其他可能的优化。

复制数据的最快方法是避免复制。如果您知道调用者代码未对obj数组进行进一步修改(这是一个重要条件),那么可能的一个技巧就是实现自定义List类以用作内部列表。在内部,您将存储共享的List<Object[]>。每次调用我们只是将新数组添加到该列表中。自定义内部列表类将知道它代表哪个列(让它为n),当它被要求在位置m处提供项目时,它将转置mn并查询内部结构以获取internalArray.get(m)[n]。这种实现是不安全的,因为调用者的限制容易被遗忘,但在某些情况下可能会更快(但是,在其他条件下这可能会更慢)。

答案 1 :(得分:0)

使用LinkedList来实现列列表。它与数据呈线性增长,为O(1)。 (如果使用ArrayList,则必须不时调整内部数组的大小。)

收集值后,您可以将链接列表转换为数组。如果N是从每个列表保持3 * N refs(每个LInkedList具有prevRef / nextRef / itemRef)到仅N refs的行数。

拥有一个用于保存不同列列表的数组会很不错,但当然,这并不是一个很大的改进,只有事先知道列数才能实现。

希望它有所帮助!

编辑测试和理论表明,ArrayList的分摊成本更好,总成本除以处理的项目数量......所以不要按照我的'建议':)

答案 2 :(得分:0)

我会尝试使用LinkedList作为内部列表,因为它应该具有更好的插入性能。也许将Object arra包装到集合中并使用addAll也可能有所帮助。

答案 3 :(得分:0)

由于数组的复制,ArrayList可能很慢(它使用与自编集合类似的方法)。

作为替代解决方案,您可以尝试简单地存储行,并在必要时创建列。这样,列表中内部数组的复制减少到最小。

示例:

//Notice: You can use a LinkedList for rows, as no index based access is used.
List<Object[]> rows =... 

List<List<Object>> columns;

public void processColumns() {
  columns = new ArrayList<List<Object>>();
  for(Object[] aRow : rows){

    while (aRow.size() > columns.size()){
      //This ensures that the ArrayList is big enough, so no copying is necessary
      List<Object> newColumn = new ArrayList<Object>(rows.size())
      columns.add(newColumn); 
    }

    for (int i = 0; i < aRow.length; i++){
      columns.get(i).add(aRow[i]);
    }
  }
}

根据列数的不同,外部列表仍然可能在内部复制数组,但普通表包含的行数远多于列数,因此它应该只是一个小数组。