Java:验证列表中是否已经存在对象?
这里详细描述了这个问题: 简而言之:由于文本文件中给出的指示,我连续访问了多个地点,我想知道我至少访问过多少个地点 我创建了一个类点,如下所示:Java:验证列表中是否已经存在对象?,java,list,Java,List,这里详细描述了这个问题: 简而言之:由于文本文件中给出的指示,我连续访问了多个地点,我想知道我至少访问过多少个地点 我创建了一个类点,如下所示: public class Point { private int x; private int y; public Point (int x, int y) { this.x=x; this.y=y; } public int getAbs() { return x; } public int
public class Point {
private int x;
private int y;
public Point (int x, int y) {
this.x=x;
this.y=y;
}
public int getAbs() {
return x;
}
public int getOrd() {
return y;
}
}
它只是一个由两个坐标组成的点,用来表示房子的位置。
我在这里使用它:
public class Exo3 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("C:/Users/mpv15_000/Documents/Advent/input3.txt");
int c = fr.read();
int x=0;
int y=0;
Point init = new Point(x,y);
List<Point> visitedHouses = new ArrayList<Point>();
visitedHouses.add(init);
Boolean b = true;
while ((c == '^') || (c == 'v') || (c == '<') || (c == '>'))
{
if (c == '^')
y++;
else if (c == 'v')
y--;
else if (c == '<')
x--;
else
x++;
for (Point p : visitedHouses) {
if ((p.getAbs() != x) || (p.getOrd() != y))
b = true;
else
b = false;
}
if (b == true) {
visitedHouses.add(new Point(x,y));
}
c = fr.read();
}
System.out.println("Number of houses visited at least once : " + visitedHouses.size());
fr.close();
}
}
公共类Exo3{
公共静态void main(字符串[]args)引发IOException{
FileReader fr=新的FileReader(“C:/Users/mpv15_000/Documents/Advent/input3.txt”);
int c=fr.read();
int x=0;
int y=0;
点初始=新点(x,y);
List visitedHouses=new ArrayList();
访问房屋。添加(初始);
布尔b=真;
while((c='^')| |(c=='v')| |(c=='')
{
如果(c=='^')
y++;
else如果(c='v')
y--;
else if(c=='当x
和y
相同时,需要重写Point类中的equals
方法以返回true。
大概是这样的:
@Override
public boolean equals(Object other)
{
if (this == other) return true;
if (!(other instanceof Point)) return false;
return (this.x == ((Point)other).x) && (this.y == ((Point)other).y);
}
然后使用集合而不是列表。集合将只包含唯一的点
如果您想继续使用列表,只需执行以下操作:
if (b == true)
{
Point visitedPoint = new Point(x,y);
if (!visitedHouses.contains(visitedPoint)) {
visitedHouses.add(visitedPoint);
}
}
顺便说一句:如何识别到访的房屋取决于您……代码部分
for (Point p : visitedHouses)
{
if ((p.getAbs() != x) || (p.getOrd() != y))
b = true;
else
b = false;
}
if (b == true)
{
visitedHouses.add(new Point(x,y));
}
看起来问题特别严重
如果你在列表中间找到“被访问”的房子,下一个条目不会(希望)是那个房子的复制品,并将“B”标志设为false,导致重复。
这是由于“缓存控制变量”的编程气味造成的。我建议您不要存储控制变量(稍后在if语句中签入的变量),以改变块的行为
Point newCandidate = new Point(x,y);
for (Point p : visitedHouses) {
if (newCandidate.getAbs() == p.getAbs() &&
newCandidate.getOrd() == p.getOrd()) {
newCandidate = null;
break;
}
}
if (newCandidate != null) {
visitedHouses.add(newCandidate);
}
但是,这仍然很像一个控制变量。如果我们只使用javaSet
像HashSet
那样的函数,速度会快得多
public Point {
... same stuff you have ...
@Override
public int hashcode() {
return 37*x + 23*y + 13;
}
@Override
public boolean equals(Object object) {
if (! object instanceof Point) {
return false;
}
Point other = (Point)object;
if (this.x != other.x) { return false; }
if (this.y != other.y) { return false; }
return true;
}
}
那你就可以了
Set<Point> visitedHouses = new HashSet<Point>();
// possibly initialize the first house
visitedHouses.add(new Point(0, 0));
while (... visiting each house ...) {
Point currentHouse = new Point(currentX, currentY);
visitedHouses.add(currentHouse);
}
Set visitedHouses=new HashSet();
//可能是第一栋房子
添加(新点(0,0));
当(…参观每家…){
点currentHouse=新点(currentX,currentY);
访问房屋。添加(当前房屋);
}
并依靠集合
界面确保在集合
中永远不会获得重复的点
条目,因为集合
不能包含重复项(并且您的点
现在知道如何获取两个实例并确定它们是否相等)
不仅最后一种方法要快得多,因为它存储在散列集中
您不需要遍历集中的每个点
来确定您是否与当前位置匹配。散列码(…)
在“用于查询集的点”上运行通过返回值进行查找可以避免99%的其他条目。然后将具有匹配哈希代码的一小部分条目与equals(…)
方法进行比较,以确定它们是否等效,或者它们是否“刚刚发生”要使用相同的hashcode。如上述问题注释中所述,您需要在找到重复点后立即中断VisitedHouse循环。
对于性能,我在循环中稍微更改了条件,请参见以下内容:
boolean found = false;
for (Point p : visitedHouses) {
if ((p.getAbs() == x) && (p.getOrd() == y)) {
found = true;
break;
}
}
if (!found) {
visitedHouses.add(new Point(x,y));
}
我不确定我是否完全理解这个问题,但是如果你想跟踪你是否看到了什么,我会使用集合而不是列表。或者为了检查成员身份,将列表放入集合。集合
不能解决这个问题吗?(除了实现hashCode
和equals
)是的,你说得对,我复制代码时出错,代码是x和y。我编辑。@MaxZoom排序列表有O(log(n))个插入和查找时间。HashSet
有O(1)个插入和查找时间。“最佳方法”是主观的。无论哪种方式,实现hashCode
和equals
都应该是这里的关键。如果if
语句没有必要,则内部语句是不必要的。Set
会自动拒绝添加元素,如果它已经包含在集合中。使用java.util.Objects.hash(x,y)
对于hashCode
来说,它可能没有那么“神奇”我不确定你认为我的评论是什么意思。我只是建议你使用内置的哈希算法而不是手动算法,以避免在实现点时使用不必要的幻数。hashCode
@4castle我可能误解了你所说的“幻数”如果是散列算法,那么你的陈述更有意义(我之前的回答大多没有抓住要点)。对于那些想“解释”我的算法的人来说,基本上是观察到相对素数在一个数字集中有很好的分布。因此,你可以取(一些素数)*x+(一些其他素数)*y+一些第三个素数
,除非你非常不走运,否则你可能有一个相对素数分布,这是一个非零的起点,这使得散列非常合适。