Java:如果存在相同参数的对象,则不添加新对象
这是我的对象构造函数
static class Edge {
int source; // source node
int destination; // destination node
int weight; // weight of the edge
int predecessor; // previous node
public Edge() {};
public Edge(int s, int d, int w) { source = s; destination = d; weight = w; }
}
现在,这是我创建一个新 Edge 对象的语句,
edges.add(new Edge(nodeStart, tempDest, tempWeight));
如果已经使用相同的参数(nodeStart,tempDest)创建了一个对象,我需要跳过该语句
基本上,我不想添加相同的边两次。
edges.add(new Edge(0, 1, tempWeight));
edges.add(new Edge(0, 1, tempWeight));
如果发生这种情况,我想确保它只添加一次,而不是添加新的相同对象。
Here is my object constructor
static class Edge {
int source; // source node
int destination; // destination node
int weight; // weight of the edge
int predecessor; // previous node
public Edge() {};
public Edge(int s, int d, int w) { source = s; destination = d; weight = w; }
}
Now, here is the statement where I create a new Edge object
edges.add(new Edge(nodeStart, tempDest, tempWeight));
I need to skip over that statement if there has already been an object created with the same parameters (nodeStart, tempDest)
Basically, I don't want to add the same edge twice.
edges.add(new Edge(0, 1, tempWeight));
edges.add(new Edge(0, 1, tempWeight));
If that happens, I want to make sure it only adds it once, and not new identical objects.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这似乎是一个工厂的候选者,您可以在工厂实现中检查现有对象的标准,并返回已经存在的对象..只是我的 2 美分...
This seems like a candidate for a factory where in you could check for an existing object for the criteria inside the factory implementation and return the one already existing.. just my 2 cents...
根据您的评论,我认为您真正需要的只是一个定制的 ArrayList。
附注,根据您对其他答案的评论,您似乎需要通过索引而不是参数进行大量随机访问。也就是说,您表明您希望按照添加边的顺序而不是通过指定唯一化参数来获取边,并且您可能希望以高度非顺序的方式访问该顺序。对于随机访问情况,此数据结构的性能将优于上面提出的自定义 Set,因为它付出了 O(N) 插入时间的高昂前期成本,其中N随着集合的大小而增长;然而,当您进行随机访问时,您将获得与
ArrayList
提供的同样出色的 O(1) 按索引检索时间。相比之下,对于自定义 Set,即使您扩展 LinkedHashSet 来维护访问顺序,您也需要花费 O(1) 插入时间,但要按顺序迭代条目,则需要 O(N),随机访问 时间。基本上,您预先支付唯一化约束,然后就忘记它。如果是套装,您需要稍后支付访问时间限制。当然,故事还没有结束,肯定有一个让双方都满意的解决方案。假设我们保留更多数据(啊,内存与 CPU/时间),并且在下面的数据结构中,我们不是通过列表搜索来找出是否已经有相关的 Edge,而是维护一个内部 Set。当我们进行插入时,我们首先尝试在集合中查找边(O(1)),当找不到边时,我们将其添加到集合和到列表。现在,我们必须保留一个额外的 Set (这就是内存成本),以避免在插入期间查看 List 的时间损失。
到目前为止一切都很好,但我们现在还需要定义一个哈希函数,它可以为您认为唯一的内容生成唯一的哈希代码。换句话说,我们要宽松地确保:
hashCode(Edge a) != hashCode(Edge b)
其中a != b
应该容纳一些令人难以置信的大空间a
和b
在您定义的某种意义上是不同的。如果您定义了这样一个函数,您仍然必须支付保留集合的内存成本,但如果您真的关心插入成本,那么这可能还不错。这是简单的直接列表概念,它很容易修改为也维护一个集合,并且如果您想使用混合方法,您可以修改下面的
contains
函数来检查集合而不是检查搜索列表。然后用法将按照您的建议进行,其中已包含在
EdgeArrayList
中的边将不会被添加:在此
foo
的末尾仅包含带有以下内容的 Edge 的第一个实例 :所有参数设置为0(我已经测试过,它确实有效)。这里有一些陷阱——检查新的
Edge
不是列表将会导致对当前列表N大小的O(N)命中。Based on your comments I think really all you need is a customized ArrayList.
On a side note, based on your comments to other answers it seems you need to do a lot of random access by index and not by parameter. That is, you indicated you want to get an Edge by the order in which it was added rather than by specifying unique-ifying parameters, and that you may want to access that order in a highly non-sequential way. For the random access case, this data structure's performance will be better than the custom Set proposed above, because it pays a high upfront-cost of O(N) insert time, where N grows with the size of the set; however, when you go to do random access you get the same great O(1) by index retrieval time that an
ArrayList
offers. In comparison, for the custom Set, even if you extend a LinkedHashSet to maintain access order you'd pay O(1) insert time, but O(N), to iterate through the entries in order, random access time.Basically, you pay the unique-ifying constraint upfront, and forget about it later. In the case of the set, you pay an access time constraint later. Of course, that's not the end of the story, there is definitely a solution which might let both worlds be satisfied. Suppose we keep more data (ah, memory vs. CPU/time), and in the data structure below instead of searching through the list to find out if we already have the Edge in question we maintain an internal Set as well. When we go to insert, we first try finding the Edge in the Set (O(1)), when the Edge is unfound, we add it to the Set and to the List. Now, we have to keep an extra Set around (that's the memory cost) to avoid a time penalty for looking at our List during inserts.
So far so good, but we now need to also define a hashing function which generates unique hashCodes for, well, what you consider unique. In other words, we want to make sure, loosely:
hashCode(Edge a) != hashCode(Edge b)
wherea != b
should hold for some unbelievably large space ofa
andb
being different in some sense you define. Given you define such a function you still have to pay the memory cost for keeping a set, but that's maybe not so bad if you really care about the insert cost.Here's the simple straight List concept, it's easily modified to also maintain a Set, and you would modify the
contains
function below to check the Set rather than check search the List if you wanted to go with the hybrid approach.Usage would then be as you suggest, where Edges already contained in the
EdgeArrayList
will simply not be added:At the end of this
foo
contains just the first instance of an Edge with all parameters set to 0 (I've tested this, it really works).Some pitfalls here -- checking that a new
Edge
is not the list will incur an O(N) hit on the order of the size of the current list N.使用 Set 而不是 List 来存储边缘对象并正确定义边缘 equals 和 hashCode。这将防止逻辑上相等的重复。
Use a Set instead of a List to store your edge objects and define the Edge equals and hashCode correctly. This will prevent duplicates which are logically equal.
要说你不想要“重复”,首先你必须告诉java你如何认为两条边相等。您可以使用
equals
方法来执行此操作(否则 java 无法知道 Edge 类的两个对象何时相等)。当您为对象提供
equals
方法时,您必须为对象提供hashCode
。请参阅此问题以获取解释。(实际上,您覆盖这些方法。这两个方法的默认实现都存在于所有java对象扩展的
java.lang.Object
中)因此,首先您必须告诉java什么时候有两个边是平等的。向您的类添加一个
equals
方法和一个hashcode
方法。有关详细信息,请参阅贾斯汀的回答。完成后,您必须确保边缘对象集合没有重复项。为此,您可以使用
HashSet
。 (而不是列表。List
可以有重复项。Set
不能。这个教程给出了很好的解释)在语句中,
edges.add...
,edges
应该是一个 HashSet(或任何集合的实现)。HashSet; Edge = new HashSet();
完成此操作后,您将拥有一个唯一边缘的列表(呃,集合)。
如果您需要仅一个List而不是集合,则可以从此
Set
创建一个List
:ArrayList EdgesAsList = new ArrayList< ;边缘>(边缘);
To say that you do not want "duplicates", first you have to tell java how you consider two edges are equal. You do this using the
equals
method (otherwise there is no way for java to know when two of the objects of your Edge class are equal).When you give a
equals
method to your object, you have to give ahashCode
to your object. See this question for an explanation.(Actually you oveerride these methods. Default implementations of both are present in
java.lang.Object
from which all java objects extend)So first you have to tell java when two Edges are equal. Add a
equals
method and ahashcode
method to your class. See Justin's answer for details.Once done, you have make sure that your collection of edge objects do not have duplicates. For this you can use a
HashSet
. (and not a List. AList
can have duplicates. ASet
cannot. This tutorial gives a good explanation)In the statement,
edges.add...
,edges
should be a HashSet (or any implementation of set).HashSet<Edge> edges = new HashSet<Edge>();
Once you have done this, you have a List (er, Set) of unique Edges.
If you need only a List and not a set, you can create a
List
out of thisSet
:ArrayList edgesAsList = new ArrayList<Edge>(edges);
另一种可能的方法是仅检查
edges.contains()
在添加新边之前。您需要在
Edge
中正确实现equals
方法才能使其正常工作。有关该代码,请参阅我的其他答案。注意:这种方式比使用
Set
排除重复项要慢得多。Another possible way is to just check
edges.contains()
before adding the new edge.You will need to properly implement the
equals
method inEdge
in order for this to work though. See my other answer for that code.Note: This way is a much slower way than using a
Set
to exclude duplicates.正确的方法是将
edges
设为Set
。然后正确覆盖 hashcode 和 equals。因此,您应该像这样声明
edges
:并且您应该像这样实现 hashCode 和 equals:
您应该阅读如何正确实现 equals 和 hashCode。我的例子并不好。但总体的想法已经传达了。
The proper way would be to make
edges
aSet<Edge>
. And then properly override hashcode and equals.So, you should declare
edges
like so:And you should implement hashCode and equals like so:
You should read up on properly implementing equals and hashCode. My examples are not great. But the general idea is conveyed.