Java 使用自定义对象消除或避免在ArrayList中添加重复项
我在这个结构中有一个自定义对象Java 使用自定义对象消除或避免在ArrayList中添加重复项,java,arraylist,duplicates,duplicate-removal,Java,Arraylist,Duplicates,Duplicate Removal,我在这个结构中有一个自定义对象 static class Node { int col; int row; int g; int h; int f; public Node(int col, int row, int g, int h) { this.col = col; this.row = row; this.g = g; this.h = h; this.f =
static class Node {
int col;
int row;
int g;
int h;
int f;
public Node(int col, int row, int g, int h) {
this.col = col;
this.row = row;
this.g = g;
this.h = h;
this.f = g+h;
}
}
列
和行
变量是唯一的,只能在ArrayList myList
中出现一次
有没有一种最佳方法可以避免添加或检查可能的重复,而不必进行讨厌的for循环
我知道
Set
接口可能是解决这一问题的一种方法,因为不会出现重复,但我现在有很多代码,除非必要,否则我不想重构这些代码。将所有元素添加到一个新的集合
,然后将集合
中的所有元素放入一个新的列表
。这就足够了。我总是觉得奇怪,当人们需要唯一性时,我想人们想要使用一个(对于get(int)
方法),这只能通过Set
实现
无论如何,通过稍微操作equals/hashcode(当行
和列
相同时,使equals返回真
)方法并向添加调用,您可以在不牺牲列表
的情况下实现目标
编辑
请注意,您还可以创建一个比较器,并依靠它对列表进行排序,并将具有相同值的项仅合并为一个值。如果可能,请在节点中添加一个equals方法:
@Override
public boolean equals(Node n){
if(this.getRow().equals(n.getRow()) && this.getCol().equals(n.getCol())
return true;
else
return false;
}
然后使用list设置为list
trick
尝试以下方法:
List<Node> removeDuplicateNodes(List<Node> inputList){
return (inputList ==null or inputList.size()==0)? Collections.EMPTY_LIST: new ArrayList<Node>(new HashSet<Node>(inputList));
}
理想情况下,您可以使用
Set
,但如果您希望避免将数据结构从ArrayList
重新实现为Set
,您可以将Set
实现为网关守护者:
- 每次将元素插入ArrayList时,请检查行-列对是否已在集合中李>
- 如果不是,则将行-列对注册到集合中
- 如果该对已存在于集合中,请不要插入它
- 每次将要从ArrayList中删除元素时,请将其从集合中删除
所有的Set操作都是
O(1)
,因为它们是散列的;最少的重构,没有令人讨厌的循环。保留一个集合和一个列表。使用集合检查重复项。如果没有重复,则添加到集合和列表
…假设节点已定义.equals方法
private final Set<Node> seen = new HashMap<Node>();
private final List<Node> uniqueNodes = new ArrayList<Node>();
public void insertIfUnique(final Node n) {
if (seen.contains(n)) {
return;
}
seen.add(n);
uniqueNodes.add(n);
}
private final Set seen=new HashMap();
private final List uniqueNodes=new ArrayList();
公共void insertIfUnique(最终节点n){
如果(见包含(n)){
返回;
}
见。添加(n);
增加(n);
}
以下是您的选择。所有这些解决方案都需要正确实现equals
和hashCode
。由于您希望行
和列
是唯一的:
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != Node.class) {
return false;
}
Node other = (Node) obj;
if (other.col != this.col) {
return false;
}
if (other.row != this.row) {
return false;
}
return true;
}
public int hashCode() {
int result = 7;
result += row * 31;
result += col * 31;
return result;
}
迭代列表
您不必自己进行迭代,但这正是调用List.contains
所要做的。这个很简单:
if (!myList.contains(node)) {
myList.add(node);
}
这将为您进行迭代,因此您不必编写循环
列表
至设置
至列表
这里有两个子选项。如果要保留输入列表的顺序,则可以使用LinkedHashSet
。如果您不在乎,您可以使用HashSet
。我的意思是,如果我有一个包含元素a、B、C的列表
,将其转换为哈希集
,然后返回可能会产生一个不同的列表,如B、C、a。LinkedHashSet
将元素保持插入顺序,从而避免了这个问题。在任何情况下,您都可以这样做:
Set<Node> nodeSet = new [Linked]HashSet<Node>(myList);
nodeSet.add(node);
myList = new ArrayList<Node>(nodeSet);
Set nodeSet=new[Linked]HashSet(myList);
添加(node);
myList=新阵列列表(节点集);
请记住,这实际上也是在进行迭代,但它使用的是哈希代码快捷方式,而不是检查每个元素的相等性,这对于足够多的节点来说可能是一件大事。如果您的节点列表很小(少于1000个元素),那么我怀疑这会造成很大的差异,您也可以使用第一个
将所有内容转换为Set
您提到这需要在代码中进行大量重构,但这并不是一件坏事,特别是如果您计划在将来大量使用此代码。我的经验是,如果重构能使代码更易于维护,那么增加一点额外的开发时间从来都不是一件坏事。编写可维护的、可读的和可理解的代码(这里的问题与此无关,但这个特定的答案与此相关)。由于
Set
意味着唯一的元素,而List
则没有,因此进行更改是有意义的。编译器几乎会告诉您所有需要更改的位置及其错误,而且所花的时间可能比您想象的要少。不要忘记重写equal()和hashCode()方法,以检查您想要实现的特定相等条件。我已经有了一个排序算法,但我正在排序一个完全不同的条件。所以,也许我可以更好地使用SET。如果我实现了SET,那么我如何根据<代码>行< /C++ >和java >代码>而不是整个元素?您可以通过重写节点的.equals()
来过滤重复项:如果您检查行和列是否相等,那么节点本身就相等。但是对于数组列表
,通过重写equals方法以同样的方式不可能做到这一点?换句话说就是这样。为了让它更干净,我应该重构到Set
并覆盖equals()
方法?我很想遍历整个列表,尽管它会变成O(N)
。这也是一个可行的选择。如果你的列表很小(就像我在回答中说的,<1000个元素),那么做所有这些事情都不会对速度产生太大影响。您可以随时使用contains
编写它,看看它是否真的那么慢。如果是
Set<Node> nodeSet = new [Linked]HashSet<Node>(myList);
nodeSet.add(node);
myList = new ArrayList<Node>(nodeSet);