Java 查找列表中所有索引的方法<;长期>;对应于某个元素

Java 查找列表中所有索引的方法<;长期>;对应于某个元素,java,list,arraylist,indexing,indices,Java,List,Arraylist,Indexing,Indices,假设我有一个名为X的long和一个名为foo的列表,其中包含X作为许多元素中的一个非唯一元素。我需要应用什么方法来查找foo中对应于X的所有索引。这个foo不一定是排序的(但是如果有一个特定的方法需要排序,那么一个好的答案可能会假设这一点——我对排序和未排序的情况都感兴趣) 例如,这可能是问题设置: long X = 5L List<Long> foo = new ArrayList<Long>(); foo.add(4L); foo.add(5L); foo.add(5

假设我有一个名为
X
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);

但是我想要一个更快的方法,以防我的
foo
非常长。

如果列表已排序,请在点击较大的对象后停止。如果列表实现允许随机访问(即
ArrayList
),则使用二进制搜索。由于列表包含重复项,因此需要从找到的元素向前和向后扫描,以确保获得所有索引

如果搜索与更新的比率很大(搜索比更新多得多),则可以在
映射中维护一个索引,该索引将每个值映射到索引列表,其中该值显示在列表中。当原始列表更新时,您必须编写代码来维护索引

在评估性能时,建立和维护索引的成本可以在搜索期间摊销。如果列表在创建后从未更新,并且搜索数量很大,那么这将是一个明显的赢家

但是,除非列表很大(>10000)并且查询数量很大(>1000000),否则可能不值得费心

试试这个解决方案:

int firstIndex = foo.indexOf(X);

int count = Collections.frequency(foo, X);
如果您的
列表
已排序,则您有两个位置:
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);
}
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);   
长X=5L
List foo=new ArrayList();
添加食物(4L);
添加食物(5L);
添加食物(5L);
foo.添加(6升);
foo.add(7L);
int firstIndex=foo.indexOf(X);//1.
int count=Collections.frequency(foo,X);//2.
列表输出=新的ArrayList();
对于(int i=firstIndex;i如果使用,则可以对源列表和索引列表使用基元列表,这样就不会产生装箱基元值的成本。以下代码将在Java 8中使用lambdas和您的示例工作:

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);
}
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的开发者。

你所说的更高效的方式是什么意思?你的列表总是被排序吗?@RohitJain比我的大列表方法运行得更快。我的列表可能会被排序,也可能不会被排序。我想要未排序和排序案例的答案。我认为你不会得到比
O(n)更好的答案
列表从一开始就非常非常低效。如果你关心效率,我不知道你为什么要使用它,或者为什么要建立匹配的索引。@PeterLawrey有什么更好的方法来保存非唯一的
long
值?如果对它进行排序,你可以使用二进制搜索来查找O(ln)中的开始和结束时间。是的,但只有当它是一个随机访问列表时,长链接列表的效率比我想象的还要低。+1 btw用于预构建索引。如果你知道正好有两个值,你就不需要查找它们。你是说
lastIndex-firstIndex+1