【问题标题】:Remove different Objects from Java ArrayList从 Java ArrayList 中删除不同的对象
【发布时间】:2020-08-23 06:09:11
【问题描述】:

我已经在这篇文章中问过这个问题:How to remove not equals Objects using ArrayList in Java

但在某些情况下,建议的解决方案不起作用。我已经尝试了其中的 2 个。 我想做的事情说起来很简单,但是当我开始用代码表达它时..它会变得混乱。

我有一个 ArrayList 书籍,我想删除一定数量的书籍 仅当它们不同时(使用等于)。

例如,如果我有 3 本不同的书,我要删除的数量是 3..那么这三本书必须被删除。假设要删除的数量不能高于 DIFFERENT 书的数量 大批。如果同一本书中有超过 1 本 ArrayList.. 例如book1 book1 book1 book2 book3,以及 quantitytoremove 是 2,那么 book1 and book2(例如)应该 被删除。输出将是book1 book1 book3只应删除另一本书的一个实例

请注意,equals 已正确覆盖。

这是我的第一个解决方案(对我来说更合乎逻辑)

public Basket removeDifferent2(int quantitytoremove) {
    System.out.println("looking at the basket before removal... of " + quantitytoremove + " different books");
    printBasket();

    // creating a copy of the books array
    List<Book> myBooks = new ArrayList(Arrays.asList(this.Books));
    // list of books to remove
    List<Book> tobeRemovedList = new ArrayList<Book>();

    // removing books from the basket according to quantitytoremove.
    for (int i = 0; i < myBooks.size() && tobeRemovedList.size() < quantitytoremove; i++) {
        for (int j = i + 1; j < myBooks.size() && tobeRemovedList.size() < quantitytoremove; j++) {
            if (!(myBooks.get(i).equals(myBooks.get(j)))
                    && !tobeRemovedList.contains(myBooks.get(j))) {
                System.out.println("Removing  Book " + myBooks.get(j).getbooknumber() + " from the basket");
                tobeRemovedList.add(myBooks.get(j));
            }
        }
    }
    myBooks = removeList(myBooks, tobeRemovedList);
    // case where there is one book left to remove that was not considered in the
    // previous loops
    if (tobeRemovedList.size() < quantitytoremove && myBooks.size() == 1) {
        System.out.println("Removing  Book " + myBooks.get(0).getbooknumber() + " from the basket");
        myBooks.remove(myBooks.get(0));
    }

    // creating the new basket without the removed books
    Book[] newbooks = new Book[myBooks.size()];
    newbooks = myBooks.toArray(newbooks);
    Basket newbasket = new Basket(newbooks);

    return newbasket;
}

private List<Book>  removeList(List<Book> list,List<Book> toRemove) {
    for (Book b : toRemove) {
        list.remove(b);
    }

    return list;
}

这是我尝试过的另一个

public Basket removeDifferent(int quantityToRemove) {
    System.out.println("looking at the basket before removal... of " + quantityToRemove + " different books");
    printBasket();
    // creating a copy of the books array
    List<Book> myBooks = new ArrayList(Arrays.asList(this.Books));
    int qn = removeDifferent(myBooks, quantityToRemove, 0, 0, 1);
    if (myBooks.size() == 1 && qn < quantityToRemove)
    myBooks.remove(0);
    // creating the new basket 
    Book[] newbooks = new Book[myBooks.size()];
    newbooks = myBooks.toArray(newbooks);
    Basket newbasket = new Basket(newbooks);

    return newbasket;
}

private int removeDifferent(List<Book> booksArray, int quantityToRemove, int qn, int i, int j) {
    if (i >= booksArray.size() || j >= booksArray.size() || qn >= quantityToRemove)
        return qn;
    if (!booksArray.get(i).equals(booksArray.get(j))) {
        System.out.println("Removing  Book " + booksArray.get(j).getbooknumber() + " from the basket");
        booksArray.remove(j);
        j--;
        qn++;
    }
    qn = removeDifferent(booksArray, quantityToRemove, qn, i, 1 + j);
    ++i;
    qn = removeDifferent(booksArray, quantityToRemove, qn, i, i + 1);
    return qn;
}

现在在这种情况下它失败了,我很难理解为什么。如您所见,缺少一本移除书,移除 3 本书后,篮子应该是这样的:

书号 1

Book mybook1 = new Book(1);
Book mybook2 = new Book(2);
Book mybook3 = new Book(3);
Book mybook4 = new Book(4);
Book mybook5 = new Book(5);

Book[] books = { mybook1,mybook1,mybook4, mybook5 };
Basket basket = new Basket(books);

Basket newbasket= basket.removeDifferent(3);
System.out.println("printing current basket..");
newbasket.printBasket();

【问题讨论】:

  • 您能否也添加BookBasket 代码以使您的示例可运行?
  • @MaksimIakunin 对于一个帖子来说这太过分了,但这些都是非常基础的课程,一本书只有一个数字,而 Basket 有一个数组。就是这样

标签: java algorithm arraylist


【解决方案1】:

我有一个使用 Java Stream API 的优雅解决方案,没有任何计数器和参数突变:

public Basket removeDifferent(int removeCount) {
    final ArrayList<Book> list = new ArrayList<>(this.books);

    new HashSet<>(this.books)
        .stream()
        .limit(removeCount)
        .forEach(list::remove);

    return new Basket(list);
}

即使removeCount 超过数组中不同书籍的数量,此方法也有效。

如果需要,您可以抛出异常:

public Basket removeDifferent(int removeCount) {
    final Set<Book> set = new HashSet<>(this.books);
    if (removeCount > set.size()) {
        throw new IllegalArgumentException(
            "removeCount cannot be greater than number of different books"
        );
    }

    final ArrayList<Book> list = new ArrayList<>(this.books);
    set.stream().limit(removeCount).forEach(list::remove);

    return new Basket(list);
}

完整的可运行示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

class Scratch {
    public static void main(String[] args) {
        Book mybook1 = new Book(1);
        Book mybook2 = new Book(2);
        Book mybook3 = new Book(3);
        Book mybook4 = new Book(4);
        Book mybook5 = new Book(5);

        Book[] books = { mybook1,mybook1,mybook4,mybook4, mybook5 };
        Basket basket = new Basket(books);

        Basket newbasket = basket.removeDifferent(5);
        System.out.println("printing current basket..");
        newbasket.printBasket();
    }

    public static class Book {
        private final int number;

        public Book(int number) {
            this.number = number;
        }

        public int getbooknumber() {
            return this.number;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Book)) return false;
            Book book = (Book) o;
            return number == book.number;
        }

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

    public static class Basket {
        private final List<Book> books;

        public Basket(Collection<Book> books) {
            this(new ArrayList<>(books));
        }

        public Basket(Book[] books) {
            this(Arrays.asList(books));
        }

        public Basket(List<Book> books) {
            this.books = books;
        }

        public Basket removeDifferent(int removeCount) {
            final ArrayList<Book> list = new ArrayList<>(this.books);

            new HashSet<>(this.books)
                .stream()
                .limit(removeCount)
                .forEach(list::remove);

            return new Basket(list);
        }

        public void printBasket() {
            books.forEach(
                book -> System.out.println("Book number " + book.getbooknumber())
            );
        }
    }
}

【讨论】:

  • 看起来棒极了哈哈
【解决方案2】:

最简单的算法是跟踪您已移除的书籍,并在移除后续的每一本书之前检查该集合。我将它表示为静态方法,因为我不知道您的 Basket 类的内部工作。

public static List<Book> removeDifferent(List<Book> books, int quantity) {
    List<Book> removals = new ArrayList<Book>();
    for (Book book : books) {
        if (!removals.contains(book)) { // contains uses .equals().
            removals.add(book);
            quantity--;
            if (quantity == 0) {
                break;
            }
        }
    }

    List<Book> result = new ArrayList(Arrays.asList(books));
    for (Book removal : removals) {
        result.remove(removal);
    }
    return result;
}

【讨论】:

  • 这不起作用,因为 .removeAll(removals) 将删除指定书籍的所有实例
  • @Hazel,对,已编辑。幸运的是 remove() 只删除了第一次出现。
  • 但这看起来和我的解决方案一样吗?
  • 两种解决方案都有大量额外的复杂性,可能会引入错误。
【解决方案3】:

使用LinkedHashSet 获取唯一元素并保持插入顺序:

static void removeDifferent(List<Book> books, int quantityToRemove) {
    Set<Book> unique = new LinkedHashSet<>(books);
    Iterator<Book> iterator = unique.iterator();
    while (iterator.hasNext() && quantityToRemove-- > 0) {
        books.remove(iterator.next());
    }
}

输出:

[1: book1, 1: book1, 3: book3]

【讨论】:

    【解决方案4】:

    查看此代码是否适合您。它检查已删除列表是否包含该项目,如果不包含该项目,则将其删除,并且在删除之前还将其添加到已删除列表中。直到删除列表的数量等于需要删除的数量

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Main {
        public static void main(String args[]) {
            List<String> books = new ArrayList<>(Arrays.asList(new String[]{"book1", "book1", "book1", "book2", "book3"}));
            System.out.println(books);
    
            books = remove(2, books);
            System.out.println(books);
        }
    
        private static List<String> remove(int i, List<String> books) {
            List<String> removed = new ArrayList<>();
    
            books.removeIf(b -> {
                boolean remove = !removed.contains(b) && removed.size() < i;
                if(remove) removed.add(b);
                return remove;
            });
            return books;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-05
      • 2013-01-26
      • 1970-01-01
      • 2010-11-21
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 2021-03-11
      相关资源
      最近更新 更多