将对象从一个ArrayList移动​​到另一个

时间:2012-06-28 21:20:21

标签: java performance arraylist

我有三个列表,我需要将动物对象从列表 animalSource 移到列表 animalTarget ,使用列表 animalFilterName 。只有名单中存在名称 animalFilterName 的动物应该从 animalSource 移动到 animalTarget ,性能明智是否有更好的方法我在下面做。现在只使用样本数据。

public class Animal {

    private String name;
    private String color;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}


public class MoveAnimal {

    /**
     * @param args
     */
    public static void main(String[] args) {

        List<Animal> animalSource = new ArrayList<Animal>();
        List<String> animalFilterName = new ArrayList<String>();
        List<Animal> animalTarget = new ArrayList<Animal>();

        animalFilterName.add("Name1");
        animalFilterName.add("Name2");

        Animal a1 = new Animal();
        a1.setColor("Color1");
        a1.setName("Name1");

        Animal a2 = new Animal();
        a2.setColor("Color2");
        a2.setName("Name2");

        Animal a3 = new Animal();
        a3.setColor("Color1");
        a3.setName("Name3");

        Animal a4 = new Animal();
        a4.setColor("Color1");
        a4.setName("Name4");

        Animal a5 = new Animal();
        a5.setColor("Color5");
        a5.setName("Name1");


        animalSource.add(a1);
        animalSource.add(a2);
        animalSource.add(a3);
        animalSource.add(a4);
        animalSource.add(a5);


        for(String s: animalFilterName) {
            for(Animal a: animalSource) {
                if(s.equals(a.getName())) {
                    animalTarget.add(a);
                }
            }
        }

    }

}

4 个答案:

答案 0 :(得分:1)

为了获得更好的性能,您需要使用Sets。我很确定你正在做的是m = animalSource.size()和n = animalFilterName.size()的O(m * n)操作,因为ArrayLists中的查找是n阶(对于列表大小)< / p>

集合中的查找,插入和删除通常是分摊的常量时间或对数时间(对于集合的大小)(取决于集合实现的具体情况),因此最坏的情况是,使用集合会将此值减少为O( m * log(n))对于相同的m和n。

Set<Animal> animalSource = ...;
Set<Animal> animalTarget = ...;
Set<String> animalFilterName = ...;

// add matching animals to new set
for (Animal a : animalSource)
    if (animalFilterName.contains(a.getName())) animalTarget.add(a);

// if you need to remove them from the first set, uncomment these lines
// for (Animal a : animalTarget)
//     animalSource.remove(a);

我认为在一行ifs和循环中省略换行使它们看起来更整洁。这是个人偏好,你没有义务复制我的风格。

编辑:固定时间复杂度

另一个编辑:当你说移动时,你的意思是添加到一个列表并从另一个列表中删除?或者你只是想添加到一个列表?

第三次编辑:修复了碎片行

答案 1 :(得分:1)

显示的算法具有复杂度O(n x m)(由于两个嵌套循环),其中n是第一个列表中元素的数量,m是过滤器中元素的数量。

要在较大的n和m值上改进算法以获得更好的性能,可以将过滤器列表转换为HashTable。

像这样:

 Hashtable<String, String> animalFilterName = new Hashtable<String, String>();
 animalFilterName.put("Name1", null);
 animalFilterName.put("Name2", null);

然后,双重for循环可以简化为:

for (Animal a: animalSource) {
    if (animalFilterName.containsKey(a.getName())) {
        animalTarget.add(a);
    }
}

现在复杂性要好得多:作为哈希表的O(n)表现为O(1)的平均值。但是你只会注意到n和m的较大数字的区别。

答案 2 :(得分:0)

有两件事情会浮现在脑海中

1)您可以制作一组过滤器并检查动物的名字是否在集合中,而不是制作过滤器列表并对其进行迭代。无论是实时更快还是取决于实际的集合大小,这在大O方面都会更好。

2)如果你既没有排序也没有随机访问,LinkedLists比ArrayLists更有效。

public static void main(String[] args) {

    List<Animal> animalSource = new LinkedList<Animal>();
    Set<String> animalFilterName = new HashSet<String>();
    List<Animal> animalTarget = new LinkedList<Animal>();

    //Set-up

    for (Animal a : animalSource) {
        if (animalFilterName.contains(a.getName())) {
            animalTarget.add(a);
        }
    }
}

答案 3 :(得分:0)

为了尊重您在sourceAnimal列表中允许重复条目的事实,我建议如下:

添加两件事:

List

类型的indexList
List<List<Integer>>

用于保存sourceAnimal列表中动物的索引。这意味着如果您有以下sourceAnimal列表

sourceAnimal: [ 0:"rabbit", 1:"dog", 2:"cat", 3:"horse", 4:"rabbit" ]

你将拥有以下(新)indexList:

indexList: [ 0: [0, 4], 1: [1], 2:[2], 3:[3] ]

当你添加最后一个附加部分时,这一切都很有意义:一个HashTable。

HashTable将动物名称映射到indexList中的相应索引,您可以在其中读取实际sourceAnimal列表中所有动物名称出现的实际索引。

有了这个,您将按如下方式处理您的任务:

// Pseudo-Code !

foreach (animal: animalFilter) {

    if (hashtable.contains(animal) {

        int superIndex = hashtable.get(animal);

        foreach (int sourceAnimalIndex : indexList[superIndex]) {

            copy sourceAnimal[sourceAnimalIndex] to targetAnimal;
        }
    }

}

}

这种方法的好处是你避免任何迭代(除了那些乘法的动物的指数,如上面的例子中“兔子”的索引0和索引4以及迭代结束你要过滤的动物。)

缺点当然可能是您必须添加其他数据结构并添加一些维护开销。

但我确信如果你在sourceAnimalList中存储了大量的项目,那么防止每个动物的整个列表上的“主迭代”将非常有效。