2D列表列表的问题

时间:2011-07-26 21:12:41

标签: java arrays list arraylist 2d

简而言之,我有一个名为 PersonList 的对象,它有一个 Person 对象列表。我创建了一个PersonLists的2D数组来模拟地图,并在该地图中随机放置和移动Person对象。但是,我在从PersonLists的2D数组中删除Persons时遇到问题。与此同时,似乎同一个人永远不会被添加到2D阵列中的相同位置,即使它移动到那里。

我已尽力创建下面的小版本。我有一种感觉,我错过了一些明显的东西。我也很开心我可以更好地实现这个系统,因为这可能是最低效的方法。

public class Person {
    private int id;
    private int[] pos = new int[2];

    public Person(int id) { this.id = id; }

    public int getId() { return id; }
    public int[] getPos() { return pos; }
    public void setPos(int x, int y) { pos[0] = x; pos[1] = y; }

    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (obj == this) { return true; }
        if (obj.getClass() != getClass()) { return false; }

        Person rhs = (Person) obj;
        return id == rhs.getId();
    }

    public int hashCode() { return id; }
}

PersonList

import java.util.*;

public class PersonList {
    List<Person> listPersons = new ArrayList<Person>();

    PersonList() {}

    public void add(Person p) { listPersons.add(p); }
    public void remove(Person p) { listPersons.remove(p); }
    public int getSize() { return listPersons.size(); }
}

现在,我还有一个控制某些人的类,并包含PersonLists的2D数组。它看起来像这样:

import java.util.*;

public class Control {
    List<Person> persons = new ArrayList<Person>();
    PersonList[][] pmap;

    //numPeople is the number of Person objects to use
    //size is the size of the pmap (used as both length and width)    
    public Control(int numPeople, int size) {
        pmap = new PersonList[size][size];
        //Initialize all PersonList objects within array
        for(int y = 0; y < size; y ++) {
            for(int x = 0; x < size; x ++) {
                pmap[x][y] = new PersonList();
            }
        }

        for(int i = 0; i < numPeople; i ++) {
            persons.add(new Person(i));
        }
        // Defined below    
        placePersons();
    }

    // Randomly place Person on the pmap    
    private void placePersons() {
        Iterator<Person> i = persons.listIterator();
        while(i.hasNext()) {
            Person p = i.next();
            int x, y;
            // Random method to obtain valid position within pmap stored in x and y
            p.setPos(x, y);
            pmap[x][y].add(p);
         }
    }

    //Move person from "src" on pmap to "dest" on pmap    
    private void movePerson(Person p, int[] src, int[] dest) {
        pmap[src[0]][src[1]].remove(p);
        pmap[dest[0]][dest[1]].add(p);
        p.setPos(dest[0], dest[1]);
    }

    //Makes every person wander around the pmap
    public void wander() {
        for(Person p : persons) {
            int[] xy = new int[2];
            // Random method to obtain valid position within pmap stored in xy
            movePerson(p, p.getPos(), xy);
        }
    }                
}

想象一下,我在循环中启动“Control.wander()”。我有一个问题,人们没有正确地从pmap中删除人员。我打印了一个网格,其中包含pmap中每个PersonList的大小,数字永远不会减少。但是,他们不会超过“人员”名单中的人数。

也就是说,它们似乎无法删除,但是不会有人将多次添加到pmap中的相同位置,即使它们移动到那里也是如此。

我的问题是否立即明显,或理论上应该有效吗?

随意提出任何问题。感谢您的帮助,我真的很感激。

编辑:我添加了一些更改 - 我现在使用迭代器而不是for-each循环,我为Person定义了一个简单的hashCode方法。作为测试,我在PlayerPos中添加了一个方法(getFirst()),它返回列表中的第0个对象,如果没有则返回null。

在movePerson中,我有类似的东西:

System.out.println(p + " and " + pmap[src[0]][src[1]].getFirst());

它期待打印两个匹配的id(我在我的测试中只使用1个人)。我还在PersonList中的remove(Person p)函数中添加了相同的行。但是,通常情况下,此结果将为“getFirst()”结果显示null。我在movePerson中测试后立即调用remove(Person p),那么为什么它会在PersonList本身内返回一些内容但是什么都没有?这是否更能说明我的问题?感谢目前为止的所有帮助。

编辑2 :我也尝试将PersonList的listPersons公开并直接操作它,但我似乎仍有同样的问题。

编辑3 :通过更多测试,在movePerson中,我已经打印出每行之间的src和dest pmap的大小,看起来它正在被正确地从src pmap中删除,但是在添加到dest之后,src pmap的大小再次增加。我已经三次检查我的添加功能(它是一个简单的单线程)并确保数组索引是正确的。怎么会发生这种情况?

3 个答案:

答案 0 :(得分:2)

private void movePerson(Person p, int[] src, int[] dest) {
    pmap[src[0]][src[1]].remove(p);
    pmap[dest[0]][src[1]].add(p);
    p.setPos(dest[0], dest[1]);
}

应该是

private void movePerson(Person p, int[] src, int[] dest) {
    pmap[src[0]][src[1]].remove(p);
    pmap[dest[0]][dest[1]].add(p); //fix on this line
    p.setPos(dest[0], dest[1]);
}

所以看起来人们被添加到他们认为不在的地方。

另请注意,您不需要将src传递给该方法,因为Person已经跟踪它的位置:

private void movePerson(Person p, int[] dest) {
    int[] pos = p.getPos();
    pmap[pos[0]][pos[1]].remove(p);
    pmap[dest[0]][dest[1]].add(p);
    p.setPos(dest[0], dest[1]);
}

修改:每当您覆盖hashCode()时,请务必覆盖equals()。如果不这样做可能会干扰List方法remove()。有人提到这个,但答案被删除了。

出于您的目的,hashCode()应该返回id,假设这是唯一的。例如,不要将位置考虑在内 - 您希望Person成为一个身份,无论他们身在何处。测试这个,然后更新你的问题,如果它仍然无效。

答案 1 :(得分:0)

PlacePersons中的随机方法是否有意注释掉了,或者您是否真的想将所有人放在[0,0]中。
我不认为PersonList类正在添加任何值,我将有如下结构:
Map<Integer, Set<Person>>

地图的整数键代表y坐标,集合中人物的位置代表x坐标。
您可以选择是否在移动时在Person类内部存储每个人坐标,或者您可以(需要付费)更改getPos以迭代Map / Set直到他们找到自己并返回那些坐标

甚至更好Map<Person, Coord>,其中Coord是一个持有x-y坐标位置的类。

请记住为Person正确实现equals和hashCode。

答案 2 :(得分:0)

使用时:

for(Person p : persons) 
{      
  int[] xy = new int[2];            
  // Random method to obtain valid position within pmap stored in xy             
  movePerson(p, p.getPos(), xy);         
} 

您正在从您的arrayList中获取对Person p的引用,然后使用foreach循环生成的符号引用来移动它们。如果您确实想在集合上使用remove操作,则需要设置迭代器。

See this for a good explaination