【问题标题】:How to filter an array in Java?如何在Java中过滤数组?
【发布时间】:2011-01-06 03:34:58
【问题描述】:

如何在 Java 中过滤数组?

我有一个对象数组,例如汽车:

类:

public class Car{
    public int doors;
    public Car(int d){
        this.doors = d;
    }
}

用途:

Car [] cars = new Cars[4];
cars[0] = new Car(3);
cars[1] = new Car(2);
cars[2] = new Car(4);
cars[3] = new Car(6);

现在我想过滤汽车数组,只保留 4 扇门或更多:

for(int i = 0; i<cars.length; i++){
    if(cars[i].doors > 4)
         //add cars[i] to a new array
    }
}

我应该怎么做?

在我使用 Vector 之前:

Vector subset = new Vector();
for(int i = 0; i<cars.length; i++){
    if(cars[i].doors > 4)
         //add cars[i] to a new array
        subset.addElement(cars[i]);
    }
}

然后我会用 Vector 的大小创建一个新数组。然后我会再次遍历向量并填充新数组。我知道对于一些简单的事情来说,这是一个非常大的过程。

我正在使用 J2ME。

【问题讨论】:

  • 你的容器是数组而不是向量真的那么重要吗?因为向量听起来很适合使用。
  • 好吧,我不能在我的环境中使用 Vector 汽车。所以我必须一直做演员表,这会变得很困难......

标签: java java-me arrays vector filter


【解决方案1】:

你可以使用System.arrayCopy():

Car[] cars = ...
int length = cars.length < 4 ? cars.length() : 4;
Car filter = new Car[4];
System.arrayCopy(cars, 0, filter, 0, length);

更新:System.arrayCopyJava ME API 中可用,与 Vector.subList() 不同。谢谢指正。

【讨论】:

  • @hsmit, System.arrayCopy() 在 Java ME 中可用,但在 Vector.subList() 中不可用。
【解决方案2】:

我看不出您的代码有什么问题。不过,您可以始终坚持使用 Vectors。

您可以使用 Vector.copyInto(Object[]) 简化第二部分(将匹配项复制到新数组中)。

【讨论】:

    【解决方案3】:

    如果你真的需要一个普通数组作为结果,我认为你的方式是要走的路:在过滤之前你不知道结果元素的数量,你不能在不知道的情况下构造一个新数组元素的数量。

    但是,如果您不需要线程安全,请考虑使用ArrayList 而不是Vector。应该会快一些。然后使用ArrayList的toArray方法获取数组。

    【讨论】:

    • 啊,好点子。所以这归结为在内存使用与速度之间进行选择:要么创建一个中间向量并从中获取数组(速度快但占用内存),要么遍历列表两次,第一次只是为了找出然后元素,然后第二次填充该大小的数组(这可能更慢,但产生的垃圾更少)。
    • 不要使用 ArrayList,如果事先不知道元素的数量,请使用 LinkedList。由于它们的内部结构,向 ArrayList 添加新字段比向 LinkedList 更昂贵。
    【解决方案4】:

    编辑: 看到 ArrayList 不在 J2ME 中,但根据文档,它确实有一个 Vector。如果该 Vector 类与 J2SE Vector 不同(如 this documentation indicates),那么下面的代码可能会起作用:

    Vector carList = new Vector();
    for(int i = 0; i<cars.length; i++){
        if(cars[i].doors > 4)
             carList.addElement(cars[i]);
        }
    }
    Car[] carArray = new Car[carList.size()];
    carList.copyInto(carArray);
    

    【讨论】:

    • carList.toArray() 在 J2ME 中不起作用,无论如何感谢您的帮助!
    • 我没有意识到 Vector 的行为不同,不妨试试我添加的第二段代码。
    • 你可能想用 cars.length 初始化向量。也许它会更有效。
    【解决方案5】:

    没有直接的方法可以从数组中删除元素;它的大小是固定的。不管你做什么,你都需要以某种方式分配一个新的数组。

    如果您想避免分配Vector 的少量内存开销,另一种选择是对您的数组进行两次传递。第一次,只需计算要保留的元素数量。然后分配一个该大小的数组,并再次遍历旧数组,将匹配的元素复制到新数组中。

    【讨论】:

    • 是的,这听起来很有趣。你对两者的表现有什么想法吗?
    • 猜测我的方法可能会更快,这取决于与所涉及的额外循环周期相比,增长向量的成本有多大。但是我对 J2ME 的性能特征了解不多,而且它还取决于您的阵列有多大等等。您必须进行基准测试才能确定。
    【解决方案6】:

    无论如何,您都需要创建一个新数组。

    Vector vector = new Vector(array.length);
    
    for (int i = 0; i < array.length; i++) {
        if (array[i].doors > 4) {
            vector.add(array[i]);
        }
    }
    
    Car[] result = new Car[vector.size()];
    vector.copyInto(result);
    

    不过,这不是很有效。

    【讨论】:

    【解决方案7】:

    执行此操作的最有效方法(如果您要过滤的谓词很便宜并且您使用单个线程访问它)通常是遍历列表两次:

    public Car[] getFourDoors(Car[] all_cars) {
      int n = 0;
      for (Car c : all_cars) if (c.doorCount()==4) n++;
      Car[] cars_4d = new Car[n];
      n = 0;
      for (Car c : all_cars) if (c.doorCount()==4) cars_4d[n++] = c;
      return cars_4d;
    }
    

    这会遍历列表两次并调用测试两次,但没有额外的分配或复制。 Vector 风格的方法遍历列表一次,但分配大约两倍的内存(暂时)并将每个好的元素复制大约两次。因此,如果您要过滤列表的一小部分(或者性能不是问题,通常不是问题),那么 Vector 方法很好。否则,上面的版本性能更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-01
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 2020-08-09
      • 2021-08-09
      • 2017-04-12
      相关资源
      最近更新 更多