有效地从 ArrayList 中获取子列表
Posted
技术标签:
【中文标题】有效地从 ArrayList 中获取子列表【英文标题】:Get a sublist from an ArrayList efficiently 【发布时间】:2015-11-19 15:06:22 【问题描述】:我的问题
我有一个包含自定义变量的固定大小的 ArrayList。尽管 ArrayList 具有固定大小,但有时它们中的很多实际上是空的。问题是我需要返回没有空变量的 ArrayList。 需要注意的重要一点: ArrayList 将首先包含其所有非空项,然后是它们下面的所有空项,例如,元素是不混合。示例:[非空,非空,....空,空,空]
我的解决方法
我虽然创建了一个 for 循环来检查(从最后一个索引到第一个索引)ArrayList 中的每个元素,以确定它是否为空。如果为空,那么我将调用此代码:
for (i = size-1; i >=0 ; i--)
groupList = new ArrayList<>(groupList.subList(0, i));
我的问题
如果 ArrayList 太大,这种方法可能会特别慢(或者不是?)。我想知道是否存在更好、对性能更友好的解决方案。 AFAIK .subList 方法很昂贵。
【问题讨论】:
.subList
方法是 O(1)。它不复制;它是超级超级便宜。
这显示了一个严重的设计问题。如果您真正想要的是一个不包含空值的可变大小列表,那么制作一个固定大小的列表并在列表中存储空值有什么意义?为什么不至少将第一个空值的索引存储在变量中?
@Rainbolt 我主要是在回答 OP 问题的最后一句话,声称“.subList 方法很昂贵。”
【参考方案1】:
您可以拥有binary search 的变体,其中您的自定义比较器是:
两个元素都为空/不为空?他们是平等的 只有一个元素为空? none null 是“更小”。您正在寻找第一个空元素。
这将花费 O(logn) 时间,其中 n
是数组的大小。
但是,获取不为空的ArrayList
的子列表(假设您要将其复制到新的列表对象)将是复制元素的线性时间,因为您必须“触摸”每个其中。
这为您提供了O(logn + k)
的总时间复杂度,其中k
是非空元素的数量,n
是数组的大小。
【讨论】:
只是改变数组的结束位置而不复制/移动它是 O(1)——这在某些语言/某些实现中应该是可能的。那么 O(logn) 呢? @brendan 是的,但是 AFAIK,特别是在 java 中,它需要创建一个自定义实现。也许ArrayList.removeRange()
有效地(可能)支持这种行为,但它是一种受保护的方法。
是的,听起来像 java...哈哈【参考方案2】:
根据您所有出色的建议,我修改了原始方法,以便我可以获取最后一个(第一个)空项目位置并只调用一次 .subList 方法。这里是:
int lastNullIndex = size - 1;
for (i = lastNullIndex; i >= 0; i--)
if (null == groupList.get(i))
lastNullIndex = i;
else
break;
groupList = new ArrayList<>(groupList.subList(0, lastNullIndex));
return groupList;
如果您认为它可以进一步修改以获得更好的性能,请告诉我们。
【讨论】:
以上是关于有效地从 ArrayList 中获取子列表的主要内容,如果未能解决你的问题,请参考以下文章
如何有效地从 NSManagedObject 中获取属性的所有有效值?