从Java中的List中收集唯一数据的最快方法

时间:2012-02-21 19:53:35

标签: java performance hashset

我的问题的基础是在Java中给出一个List对象,什么是返回唯一数据集合的最快方法?

更具体的版本是,我有一个2d ArrayList(想象它就像一个表),我想循环遍历给定的列索引并返回唯一数据。

这是我当前的设置:

public Set<Object> getDistinctColumnData( int colIndex ) { 

    //dataByIndex = List<List<Object>>

    Set<Object> colDistinctData = new HashSet<Object>( dataByIndex.size() + 1, 1f ) ;

    for( List<Object> row : dataByIndex ) { 
        colDistinctData.add( row.get( colIndex ) ) ;
    }

    return colDistinctData ; 

}

当我将初始容量设置为非独特集合的大小加上1并且负载因子为1时,我获得了小的性能提升(我的想法是它赢得了不需要增长直到达到100%,即使原始集合已经100%不同(或者我错了吗?),也不会发生这种情况。)

有更快的方法吗?

3 个答案:

答案 0 :(得分:0)

我认为如果你只有两个独特的收藏品会更快。维护dataByIndex列表,还维护一个dataSet Collection(Set)。当您插入dataByIndex列表时,也会将其放入您的dataSet Set中。然后只需在需要的地方使用您的dataSet。该集合将保持作为集合的本质的唯一性。

答案 1 :(得分:0)

我认为在为您指定的值设置容量和加载因子方面没有多大意义。您使用什么散列函数?可能会降级到链表吗?

答案 2 :(得分:0)

如果你更多地增加HashSet的初始容量,你可能会进一步提升性能(平均)。这是因为列表中对象的哈希值的分布可能更容易发生冲突。

例如,给定以下列表,除了第一次插入之外的所有内容都将导致冲突,尽管没有重复值。 (整数的Java哈希函数是整数本身的值,HashSet在发生冲突时使用开放寻址和线性探测)。

[0,10,1,2,3,4,5,6,7]

或更糟糕的是,因为每个插入都必须在插入之前检查每个非空闲空间。

[0, 5, 25, 125]

在最后一个例子中,0被放入索引0. 5最初进入索引0,因为5%大小(即5)等于0,所以然后转到索引1. 125将转到索引0,但是0到达0索引0,5在索引1处,25处在索引2处。这意味着在三次检查之后125最终可以在索引3处插入。

如果增加初始容量,则会降低碰撞的概率(平均),并且如果发生碰撞(也平均),则减少所需的检查次数。默认情况下,java使用0.75的加载因子作为性能和内存使用之间的良好平衡。因此除以负载系数0.75,加1应该给你一个良好的初始容量。