给定一个旧数组和一组需要跳过的索引位置,如何构造一个新数组?

时间:2014-04-10 03:08:01

标签: java arrays algorithm

基本上我想要的是我跳过集合中那些索引值的元素,否则我应该将旧数组元素推入新数组。

因此,如果我的集合包含[2,4,9,10],我应该跳过旧数组中索引2,4,9,10的值,并将值放在我的新数组中的其他索引位置。

我正在编写像这样的代码

  int[] newArr = new int[oldArray.length - set.size()];


   for(int i = 0, j = 0; j < newArr.length && i < oldArray.length; j++,i++){
      if(set.contains(i) )
         i++;
       else
         newArray[j] = oldArray[i];
      }

我正在创建并填充我的套装

       Set<Integer> commonSet = new HashSet<>();

       for(int i = 0; i < array1; i++ ){
         for(int j= 0; j < array2; j++) {
            if(arrayOne[i] == arrayTwo[j]){
              commonSet.add(i);// Here I am saving the indices.
           }
         }
       }

不确定这是否是最佳方式。还有其他更有效的方法吗? 或者我必须使用像ArrayLists这样的Collection类。

3 个答案:

答案 0 :(得分:2)

使用Collection类而不是数组会使代码更简单。

使用apache CollectionUtils等常用库进行数组减法如下所示:

    Collection<Integer> diff = CollectionUtils.subtract(Arrays.asList(array1), Arrays.asList(array2));

除非您打算使用非常大量数据,否则它不会对速度产生明显影响。

另外,按照上面的方式创建一组不同的索引,对于较大的数据集,其扩展性会非常差。只需使用CollectionUtils.subtract()与设置的创建代码计算差异的时间,就会显示缩放问题(填充了随机Integers的数组):

array1.length = 1000
array2.length = 1000
diff.size() = 530
elapsed ms for calculating diff = 39
set creation ms = 7

array1.length = 10000
array2.length = 10000
diff.size() = 5182
elapsed ms for calculating diff = 47
set creation ms = 519

array1.length = 50000
array2.length = 50000
diff.size() = 26140
elapsed ms for calculating diff = 101
set creation ms = 12857

array1.length = 1000000
array2.length = 1000000
diff.size() = 524142
elapsed ms for calculating diff = 1167
(didn't bother to wait for the program to finish)

正如你所看到的,做一个双循环比较每个元素的比例很差,而且甚至不计算你之后必须做的减法。

更新了EDIT以反映问题的变化

答案 1 :(得分:1)

如果您担心性能,绝对使用任何列表或集合类。它们因频繁重新分配数组而臭名昭着,因为它们需要更多容量,这是一个非常慢的操作。

不幸的是,我不知道如何创建/填充set个索引。如果您也可以将数组放在数组中并以对其条目进行排序的方式生成它,则可以显着优化代码。

如果setoldArray相比相当长,请执行此操作(假设set中没有重复的条目!):

int l = oldArray.length; // Cache length (some compilers might do this for you)
for (int i=0, j=0, k=0; i<l; i++) {
    if (set[k]==i) {
        k++;
    } else {
        newArr[j++] = oldArray[i];
    }
}

如果set相当短,请执行此操作(这可以处理重复的条目,但仍需要对set进行排序):

int o1=0;
int o2=0;
for (int p:set) {
    System.arraycopy(oldArray, o1, newArr, o2, p-o1);
    o1+=p+1;
    o2+=p;
}
System.arraycopy(oldArray, o1, newArray, o2, oldArray.length-o1);

前者避免了函数调用,而后者依赖于System.arraycopy(...)的优化内存复制实现(并且set可以是任何已排序的Iterable,尽管数组会更快)。

哪一个更快将取决于阵列的确切大小以及您使用的系统(CPU,JVM)。

如果set未排序,您可以使用您的方法(当然是已调试),也可以先对其进行排序,然后使用其中一种方法。同样,哪一个会为您提供更好的性能取决于set和您的系统的大小。

答案 2 :(得分:0)

这段代码正在为我做这件事。 谢谢@ Patricia Shanahan

         int j = 0, i = 0;
         while( j < newArr.length && i < oldArray.length){

           if(commonSet.contains(i)){
                i++;
               }
           else{
               diffArray[j] = arrayOne[i];
               j++;
               i++;
             }
          }