简体   繁体   English

如何删除 Java 中 ArrayList 中的重复项之一

[英]How to remove ONE of the duplicates in an ArrayList in Java

I have an ArrayList filled with a number of the same books.我有一本 ArrayList,里面装满了许多相同的书。 Now I need to be able to implement a method lendBook (String bookName, String lenderName) that removes the last one of this list.现在我需要能够实现一个方法lendBook (String bookName, String lenderName)来删除这个列表的最后一个。 If I use books.get(bookName).remove(book) nothing happens.如果我使用books.get(bookName).remove(book)什么都不会发生。 If I use books.get(bookName).remove(books.get(bookName).get(books.get(bookName).size()-1)) it removes the whole ArrayList.如果我使用books.get(bookName).remove(books.get(bookName).get(books.get(bookName).size()-1))它会删除整个 ArrayList。 Thanks for your help in advance.提前感谢您的帮助。

public class Library extends HashMap {

    public Map<String, ArrayList<Book>> books;
    protected Map<String, Lender> lenders;

    public Library() {
        this.books = new HashMap<String, ArrayList<Book>>();
        this.lenders = new HashMap<String, Lender>();
    }


    public void addBook (String bookName){
        String key = bookName;
        if (books.containsKey(key)){
           books.get(key).add(new Book(bookName));
        } else {
            books.put(bookName, new ArrayList<Book>());
            books.get(key).add(new Book(bookName));
        }
    }

    public void addLender (String lenderName) throws java.lang.IllegalStateException {
        String key = lenderName;
        if (lenders.containsKey(key)){
            throw new java.lang.IllegalStateException(lenderName);
        } else {
            lenders.put(lenderName, new Lender(lenderName));
        }
    }
}

One solution might be to check for the last index in the ArrayList.一种解决方案可能是检查 ArrayList 中的最后一个索引。 You can see the size of the ArrayList with ArrayList.size().您可以使用 ArrayList.size() 查看 ArrayList 的大小。 So for instance所以例如

int size = ArrayList.size();

Then remove the last index.然后删除最后一个索引。

The data structure you are using to store the books is a hashmap of String and an arraylist.您用于存储书籍的数据结构是字符串的 hashmap 和 arraylist。 Assuming the string to be book Name and arrayList containing of multiple book objects of the same book from which you want to delete last book假设字符串为 book Name 和 arrayList 包含要从中删除最后一本书的同一本书的多个书籍对象

ArrayLiat<Book> booksForName = books.get(bookName);

Now to remove the last element of this list you just need to do现在要删除此列表的最后一个元素,您只需要做

booksForName.removes(books.size()-1);

This can simply be done in a single line but the code will.这可以简单地在一行中完成,但代码会。 be messy and not so easy to understand if you try reading after a few weeks:P如果您在几周后尝试阅读,就会变得凌乱且不容易理解:P

First, as commented , you should not be extending HashMap .首先, 正如评论的那样,您不应该扩展HashMap Plus, I do not see how you were using Library as a Map .另外,我看不到您如何将Library用作Map

Your use of the word "duplicates" in the title is misleading, as we are not dealing with duplicates of identical data.您在标题中使用“重复”一词具有误导性,因为我们不处理相同数据的重复。 Instead, apparently you want to track multiple copies of a book.相反,显然您想跟踪一本书的多个副本

You need to think through the problem domain to arrive at a proper data structure.您需要仔细考虑问题域以得出正确的数据结构。 A book is a concept (and a piece of intellectual property), with a title, an author(s), an identifier (ISBN etc.), a classification (such a Dewey Decimal number), and so on.一本书是一个概念(和一块知识产权),具有标题、作者、标识符(ISBN 等)、分类(例如杜威十进制数)等。 Individual physical copies of a book are something else.一本书的单个物理副本是另一回事。 Attributes of a copy include the identifier stamped on each by a librarian, and its condition as noted by a librarian.副本的属性包括由图书管理员标记在每个副本上的标识符,以及图书管理员记录的其状况。 In our data model we would track the BookCopy objects as children related to a parent Book object.在我们的数据 model 中,我们将跟踪BookCopy对象作为与父Book object 相关的子对象。

Your desire that the lending method "removes the last one of this list" must mean that you want to lend our books per a LIFO policy: Last one in is first one out.您希望借阅方法“删除此列表的最后一个”必须意味着您希望按照 LIFO 政策借出我们的书籍:后进先出。 Rather than use ArrayList as your collection, use an implementation of the interface meant for this purpose: Deque .不要使用ArrayList作为您的集合,而是使用用于此目的的接口的实现: Deque ArrayDeque might be a good implementation for your purpose. ArrayDeque对于您的目的可能是一个很好的实现。

Actually, Deque is a bit confusing, as it can be used in different ways.实际上, Deque有点令人困惑,因为它可以以不同的方式使用。 For LIFO (Last-in, First-out) behavior, call:对于 LIFO(后进先出)行为,请调用:

As for adding items to your maps, your books and lenders maps are what is known as a multimap .至于向您的地图添加项目,您的bookslenders地图就是所谓的多地图 The "multi" refers to multiple values per key rather than a single value per key. “多”是指每个键的多个值,而不是每个键的单个值。

Java now has built-in support for multimaps via the computeIfAbsent feature added to Java 8. Java 现在通过添加到 Java 8 的computeIfAbsent功能内置了对多图的支持。

Take for example this BookCopy class.以这BookCopy We use enum Condition for a librarian to record the physical condition of each book copy.我们对图书管理员使用 enum Condition来记录每本书的物理状况。 We use a UUID value as an identifier to be stamped on each book by the librarian.我们使用UUID值作为标识符,由图书管理员在每本书上盖章。

package work.basil.example;

import java.util.Objects;
import java.util.UUID;

public class BookCopy
{
    public enum Condition
    { PRISTINE, GOOD, SERVICABLE, DELAPIDATED }

    ;

    // Member fields
    private UUID uuid;
    private Condition condition;

    // Constructor
    public BookCopy ( UUID uuid , Condition condition )
    {
        this.uuid = Objects.requireNonNull( uuid );
        this.condition = Objects.requireNonNull( condition );
    }

    // Accessors

    public UUID getUuid ( ) { return this.uuid; }

    public Condition getCondition ( ) { return this.condition; }

    public void setCondition ( Condition condition ) { this.condition = condition; }

    // Object

    @Override
    public boolean equals ( Object o )
    {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        BookCopy bookCopy = ( BookCopy ) o;
        return uuid.equals( bookCopy.uuid );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( uuid );
    }

    @Override
    public String toString ( )
    {
        return "BookCopy{ " +
                "uuid=" + uuid +
                " | condition=" + condition +
                " }";
    }
}

Apparently you want to track which copies are available at the library for lending.显然,您想跟踪图书馆有哪些副本可供借阅。 For each book, we need a Deque containing copies available for loan.对于每本书,我们都需要一个包含可供借阅的副本的Deque If we track each book by its title as a String , we would have a Map where the key is String (title), and the value is a Deque of BookCopy objects.如果我们按标题作为String跟踪每本书,我们将有一个Map ,其中键是String (标题),值是BookCopy对象的Deque

Map < String , Deque < BookCopy > > copiesOnHand = new HashMap <>();

As mentioned above, you really should have a Book class in addition to a BookCopy class.如上所述,除了BookCopy class 之外,您确实应该拥有Book class。 If so, would use a Book object rather than merely the title String .如果是这样,将使用Book object 而不仅仅是标题String

Map < Book , Deque < BookCopy > > copiesOnHand = new HashMap <>();

But for the sake of simplicity in this short demo, we will stick to using a String title to represent the book.但是为了在这个简短的演示中简单起见,我们将坚持使用String标题来表示这本书。

First, we add book copies to that map.首先,我们将书籍副本添加到 map。 The computeIfAbsent line first checks to see if your specified key has an entry in the map with a non-null value. computeIfAbsent行首先检查您指定的键是否在 map 中具有非空值的条目。 If not, the value (an empty ArrayDeque ) is instantiated and added.如果不是,则实例化并添加该值(一个空的ArrayDeque )。

// Two copies of this book to lend.
String title = "Java Concurrency in Practice";

BookCopy bookCopy1 = new BookCopy( UUID.fromString( "61f036b5-da62-41fe-a765-f76bc31eebcb" ) , BookCopy.Condition.PRISTINE );
copiesOnHand.computeIfAbsent(
        title ,                                // key.
        ( String key ) -> new ArrayDeque <>()
)
        .addFirst( bookCopy1 );                      // value.

BookCopy bookCopy2 = new BookCopy( UUID.fromString( "731010a2-623a-4200-963a-9ce18f4fe988" ) , BookCopy.Condition.SERVICABLE );
copiesOnHand.computeIfAbsent(
        title ,                                // key.
        ( String key ) -> new ArrayDeque <>()
)
        .addFirst( bookCopy2 );                      // value.

Lending means we remove and return the last item in the deque.借出意味着我们删除并返回双端队列中的最后一项。

// Debug: See our current inventory.
System.out.println( "copiesOnHand = " + copiesOnHand );

// Lend a book.
BookCopy copyToLend = copiesOnHand.computeIfAbsent(
        title ,                                // key.
        ( String key ) -> new ArrayDeque <>()
)
        .removeFirst();
if ( Objects.nonNull( copyToLend ) )
{
    System.out.println( "Lending book copy ID: " + copyToLend.getUuid() );
} else
{
    System.out.println( "Sorry, no copies of that book available to lend. " );
}

// Debug: Review our inventory after lending.
System.out.println( "copiesOnHand = " + copiesOnHand );

When run.跑的时候。

copiesOnHand = {Java Concurrency in Practice=[BookCopy{ uuid=731010a2-623a-4200-963a-9ce18f4fe988 | CopyOnHand = {Java 并发实践=[BookCopy{ uuid=731010a2-623a-4200-963a-9ce18f4fe988 | condition=SERVICABLE }, BookCopy{ uuid=61f036b5-da62-41fe-a765-f76bc31eebcb |条件=服务},BookCopy {uuid=61f036b5-da62-41fe-a765-f76bc31eebcb | condition=PRISTINE }]}条件=原始 }]}

Lending book copy ID: 731010a2-623a-4200-963a-9ce18f4fe988借书本ID:731010a2-623a-4200-963a-9ce18f4fe988

copiesOnHand = {Java Concurrency in Practice=[BookCopy{ uuid=61f036b5-da62-41fe-a765-f76bc31eebcb | CopyOnHand = {Java 并发实践=[BookCopy{ uuid=61f036b5-da62-41fe-a765-f76bc31eebcb | condition=PRISTINE }]}条件=原始 }]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM