繁体   English   中英

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

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

我有一本 ArrayList,里面装满了许多相同的书。 现在我需要能够实现一个方法lendBook (String bookName, String lenderName)来删除这个列表的最后一个。 如果我使用books.get(bookName).remove(book)什么都不会发生。 如果我使用books.get(bookName).remove(books.get(bookName).get(books.get(bookName).size()-1))它会删除整个 ArrayList。 提前感谢您的帮助。

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));
        }
    }
}

一种解决方案可能是检查 ArrayList 中的最后一个索引。 您可以使用 ArrayList.size() 查看 ArrayList 的大小。 所以例如

int size = ArrayList.size();

然后删除最后一个索引。

您用于存储书籍的数据结构是字符串的 hashmap 和 arraylist。 假设字符串为 book Name 和 arrayList 包含要从中删除最后一本书的同一本书的多个书籍对象

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

现在要删除此列表的最后一个元素,您只需要做

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

这可以简单地在一行中完成,但代码会。 如果您在几周后尝试阅读,就会变得凌乱且不容易理解:P

首先, 正如评论的那样,您不应该扩展HashMap 另外,我看不到您如何将Library用作Map

您在标题中使用“重复”一词具有误导性,因为我们不处理相同数据的重复。 相反,显然您想跟踪一本书的多个副本

您需要仔细考虑问题域以得出正确的数据结构。 一本书是一个概念(和一块知识产权),具有标题、作者、标识符(ISBN 等)、分类(例如杜威十进制数)等。 一本书的单个物理副本是另一回事。 副本的属性包括由图书管理员标记在每个副本上的标识符,以及图书管理员记录的其状况。 在我们的数据 model 中,我们将跟踪BookCopy对象作为与父Book object 相关的子对象。

您希望借阅方法“删除此列表的最后一个”必须意味着您希望按照 LIFO 政策借出我们的书籍:后进先出。 不要使用ArrayList作为您的集合,而是使用用于此目的的接口的实现: Deque ArrayDeque对于您的目的可能是一个很好的实现。

实际上, Deque有点令人困惑,因为它可以以不同的方式使用。 对于 LIFO(后进先出)行为,请调用:

至于向您的地图添加项目,您的bookslenders地图就是所谓的多地图 “多”是指每个键的多个值,而不是每个键的单个值。

Java 现在通过添加到 Java 8 的computeIfAbsent功能内置了对多图的支持。

以这BookCopy 我们对图书管理员使用 enum Condition来记录每本书的物理状况。 我们使用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 +
                " }";
    }
}

显然,您想跟踪图书馆有哪些副本可供借阅。 对于每本书,我们都需要一个包含可供借阅的副本的Deque 如果我们按标题作为String跟踪每本书,我们将有一个Map ,其中键是String (标题),值是BookCopy对象的Deque

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

如上所述,除了BookCopy class 之外,您确实应该拥有Book class。 如果是这样,将使用Book object 而不仅仅是标题String

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

但是为了在这个简短的演示中简单起见,我们将坚持使用String标题来表示这本书。

首先,我们将书籍副本添加到 map。 computeIfAbsent行首先检查您指定的键是否在 map 中具有非空值的条目。 如果不是,则实例化并添加该值(一个空的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.

借出意味着我们删除并返回双端队列中的最后一项。

// 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 );

跑的时候。

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

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

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

暂无
暂无

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

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