从ArrayList中仅依据一个属性删除对象

9
我有一个Item的ArrayList,我想通过输入其中一个Item属性,例如其编号(int ItemNumber),仅删除列表中的一个Item。当我检查Item数量时,也希望能做同样的事情。
这是我的equals()和contains()方法,我需要在这里做出任何更改吗?
public boolean contains(T anEntry) {
    boolean found = false;
    for (int index = 0; !found && (index < numberOfEntries); index++) {
    if (anEntry.equals(list[index])) 
        found = true;
    }//end for
    return found;
} // end contains

public boolean equals(Object object){
    Item item = (Item) object;
    if (itemNo == item.itemNo)
        return true;
    return false;
}

1
我认为你应该考虑使用 Map 而不是 List。 - beresfordt
5
抱歉,但我甚至不知道那段代码是从哪里来的。它是包含项目(在列表中)的类吗?那为什么要在那里重写等于方法?或者你是把两个来自不同类的方法放在同一个代码块中吗?这让人感到困惑... - Florian Schaetz
4个回答

8
如果您更改Item类的equals()compareTo()方法,使其仅检查一个对象字段,例如quantity,则可能会导致应用程序的其他部分出现奇怪的行为。例如,两个具有不同itemNoitemNameitemPrice,但具有相同数量的物品可能被认为是相等的。此外,您将无法在不每次更改equals()代码的情况下更改比较属性。
此外,创建自定义contains()方法没有意义,因为它属于ArrayList类,而不是Item类。
如果您可以使用Java 8,则一种清洁的方法是使用新的CollectionremoveIf方法:
假设您有一个具有numname属性的Item类:
class Item {
    final int num;
    final String name;

    Item(int num, String name) {
        this.num = num;
        this.name = name;
    }
}

假设有一个名为itemsList<Item>以及一个名为numberint变量,代表你想要移除的项目编号,你可以简单地执行以下操作:

items.removeIf(item -> item.num == number);

如果您无法使用Java 8,您可以通过使用自定义比较器、二分查找和虚拟对象来实现此目的。
您可以为每个需要查找的属性创建一个自定义比较器。对于num的比较器将如下所示:
class ItemNumComparator implements Comparator<Item> {
    @Override
    public int compare(Item a, Item b) {
        return (a.num < b.num) ? -1 : ((a.num == b.num) ? 0 : 1);
    }
}

然后,您可以使用比较器对列表中的所需元素进行排序和搜索:
public static void main(String[] args) {
    List<Item> items = new ArrayList<>();
    items.add(new Item(2, "ball"));
    items.add(new Item(5, "cow"));
    items.add(new Item(3, "gum"));

    Comparator<Item> itemNumComparator = new ItemNumComparator();
    Collections.sort(items, itemNumComparator);

    // Pass a dummy object containing only the relevant attribute to be searched
    int index = Collections.binarySearch(items, new Item(5, ""), itemNumComparator);
    Item removedItem = null;
    // binarySearch will return -1 if it does not find the element.
    if (index > -1) {
        // This will remove the element, Item(5, "cow") in this case, from the list
        removedItem = items.remove(index);
    }
    System.out.println(removedItem);
}

要搜索另一个字段,比如姓名,你需要创建一个姓名比较器并使用它来对列表进行排序和运行二分搜索。
请注意,这种解决方案也有一些缺点。除非你完全确定列表自上次排序以来没有改变,否则在运行binarySearch()方法之前,你必须重新对其进行排序。否则,它可能无法找到正确的元素。排序复杂度为O(nlogn),因此根据列表的大小多次运行它可能会变得相当昂贵。

它不起作用 :( 我认为分离的类存在问题。我能否实现一个名为CompareTo的方法,使其能够与上述的contains()和equals()方法一起使用? - helloworld
你遇到了什么问题?只检查一个属性的compareTo和equals方法可能会导致在使用Item对象的代码的其他部分出现奇怪的行为。 - Anderson Vieira
问题在于你可能正在使用Java 6,它没有Integer.compare()方法。我更新了答案,请尝试现在使用compare()方法。我还解释了将equals()更改为仅检查一个属性的问题。compareTo()方法几乎与上面的compare()方法相同,但它将在Item类中实现,并仅接受一个Item对象作为参数。 - Anderson Vieira
是的,这就是我想做的,但我不知道如何实现CompareTo()方法。因为我以后也需要它来实现另一个名为“checkquantity(int limit)”的方法,该方法将把数量小于限制的项目移到列表的前面。由于我在Java方面没有很好的背景,所以我无法想出正确的实现CompareTo()的方法。 - helloworld
请查看此教程:http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html - Anderson Vieira
显示剩余3条评论

1

您想删除特定索引处的对象吗?我不完全确定您所说的“number field”的含义。如果是这样,请跳转到remove(int)方法:

http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove%28int%29

编辑:如果您想查找/调整数组列表中对象的字段,您可以使用以下代码(我自己的代码片段):

public boolean studentHasISBN(ArrayList<Student> st, String s){
    for(Student j : st) {
        if(s.equals(j.getRentedBookISBN()))
            return true;
    }
    return false;
}

你只需要遍历列表,并搜索要查找的字段,然后使用remove(int)方法即可。


我有一个名为Items的类,具有以下属性(ItemNumber,ItemName,ItemPrice,Quantity)。 我想仅使用ItemNumber属性删除整个项目,怎么做? - helloworld

1

只需使用 Java 中的 ArrayListsremove 函数即可:

theNameOfYourArrayList.remove(ItemNumber);

要删除具有索引 (int ItemNumber) 的元素

要检查项目编号为 (int ItemNumber) 的元素是否存在于您的ArrayList中(假设名为theNameOfYourArrayList):

theNameOfYourArrayList.get(ItemNumber);

我要如何检查我的列表中是否存在这个ItemNumber? - helloworld

1

我假设你所说的“数字字段”是指你使用了Integer数据类型来调用ArrayList。我有几种不同的解决方案来解决你的问题:

  1. 假设ArrayList是ArrayList<Integer> numList = new ArrayList<Integer>();,您可以编写一个简单的方法来搜索“numList”并删除数字所在的索引。问题在于,在ArrayList中使用contains和find可能会很慢。

    public void deleteNumField(int field) { // 如果field实际上不在numList中,这将阻止任何错误 // 它将删除ArrayList中字段的第一个索引 if(numList.contains(field)) numList.remove(numList.find(field)); }

  2. HashSets是一种方便的数据类型,类似于ArrayList,但其数据是其“索引”(有点像)。我不会深入介绍它们的工作原理,但我会说在其中进行搜索被认为是O(1)。这将使您的删除变得非常容易和快速。注意:HashSet假定没有重复的数字,如果有,请使用HashMap。

    HashSet<Integer> numList = new HashSet<Integer>(); public void deleteNumField(int field) { // 这将防止尝试删除不存在的元素而产生错误,并在存在时删除它。 if(numList.contains(field)) numList.remove(field); }


如果需要了解有关HashMap、HashSet和ArrayList的更多信息,请参阅: http://docs.oracle.com/javase/8/docs/api/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接