假设我有一个名为long
的{{1}}和一个名为X
的{{1}},其中包含List<Long>
作为众多元素中的一个非唯一元素。我需要应用什么方法来查找foo
中与X
对应的所有索引。这个foo
不一定是排序的(但如果有一个需要排序的特定方法,那么一个好的答案可能会假设这一点 - 我对排序和未排序的情况感兴趣)。
例如,这可能是问题设置:
X
我希望该方法接受foo
作为参数并返回包含索引long X = 5L
List<Long> foo = new ArrayList<Long>();
foo.add(4L);
foo.add(5L);
foo.add(5L);
foo.add(6L);
foo.add(7L);
和X
的列表(或其他对象),因为它们对应于{的位置{1}}内的{1}}。
中平凡,
1
但我想要更快的方式,因为我的2
非常长。
答案 0 :(得分:1)
如果列表已排序,请在点击更大的内容后停止。如果列表实现允许随机访问(即ArrayList
),则使用二进制搜索。由于列表包含重复项,因此您需要从找到的元素向前和向后扫描,以确保获得所有索引。
如果搜索与更新的比率很大(搜索次数多于更新次数),那么您可以在Map<Long,List<Integer>>
中维护一个索引,该索引将每个值映射到值列表中显示的索引列表。在原始列表更新时,您必须编写代码来维护索引。
在评估绩效时,建立和维护索引的成本可以在搜索中摊销。如果列表在创建后永远不会更新,并且搜索次数很多,那么这将是一个明显的赢家。
但是,除非列表很大(> 10000)并且查询数量很大(> 1,000,000),否则可能不值得。
答案 1 :(得分:1)
如果使用GS Collections,则可以对源列表和索引列表使用原始列表,因此不会产生装箱原始值的成本。以下代码可以在Java 8中使用lambdas和您的示例:
long X = 5L;
LongArrayList list = LongArrayList.newListWith(4L, 5L, 5L, 6L, 7L);
IntArrayList indices = new IntArrayList();
list.forEachWithIndex((each, index) -> { if (each == X) indices.add(index);});
Assert.assertEquals(IntArrayList.newListWith(1, 2), indices);
在Java 7中,它看起来如下:
long X = 5L;
LongArrayList list = LongArrayList.newListWith(4L, 5L, 5L, 6L, 7L);
IntArrayList indices = new IntArrayList();
list.forEachWithIndex(new LongIntProcedure()
{
public void value(long each, int index)
{
if (each == X) indices.add(index);
}
});
Assert.assertEquals(IntArrayList.newListWith(1, 2), indices);
注意:我是GS Collections的开发人员。
答案 2 :(得分:0)
试试这个解决方案:
int firstIndex = foo.indexOf(X);
int count = Collections.frequency(foo, X);
如果您的List
已排序,则您有2个职位:firstIndex
和firstIndex + 1
从你的例子:
long X = 5L
List<Long> foo = new ArrayList<Long>();
foo.add(4L);
foo.add(5L);
foo.add(5L);
foo.add(6L);
foo.add(7L);
int firstIndex = foo.indexOf(X); // 1
int count = Collections.frequency(foo, X); // 2
List<Long> output = new ArrayList<Long>();
for(int i=firstIndex; i<count; i++ ){
output.add(i);
}