Удалить разные объекты из Java ArrayList - PullRequest
1 голос
/ 07 мая 2020

Я уже задавал этот вопрос в этом посте: Как удалить объекты not equals с помощью ArrayList в Java

Но в некоторых случаях предлагаемое решение не работает. Я пробовал 2 из них. То, что я хочу сделать, довольно просто сказать, но когда я начинаю express это в коде ... он становится беспорядочным.

У меня есть ArrayList книг, и я хочу удалить определенное число книг, только если они разные (с использованием одинаковых).

Например, если у меня есть 3 разных книги, а количество моих удаляемых книг равно 3 .., то эти 3 книги должны быть удалены. Предполагая, что количество удаленных книг не может быть больше, чем количество РАЗНЫХ книг внутри массива. В случаях, когда в 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;
}

теперь в этом случае он не работает, и это сложно для меня чтобы понять почему. Как видите, отсутствует одно удаление, и после удаления трех разных книг корзина должна выглядеть примерно так:

Номер книги 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();

enter image description here

Ответы [ 4 ]

2 голосов
/ 07 мая 2020

У меня есть элегантное решение, использующее 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())
            );
        }
    }
}
1 голос
/ 07 мая 2020

Использование 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]
1 голос
/ 07 мая 2020

Посмотрите, работает ли этот код для вас. Он проверяет, содержит ли удаленный список элемент, затем удаляет его, если он не содержит его, и перед удалением также добавляет его в удаленный список. Пока количество удаленных списков не станет равным количеству, необходимому для удаления

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

enter image description here

1 голос
/ 07 мая 2020

Самый простой алгоритм - отслеживать книги, которые вы удалили, и сравнивать их с этим набором перед удалением каждой последующей книги. Я express это как метод stati c, так как я не знаю внутренней работы вашего 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...