I am creating a phone book program and need a method to remove an entry from the directory depending on what name or phone number the user enters.
So far I have the following code:
public void deleteEntry(String string) {
for(Entry e : phonebook){
if (e.getFirstName().equalsIgnoreCase(string)){
phonebook.remove(e);
System.out.println("Entry " + e.toString() + " removed");
}
else {
System.out.println("Entry not deleted");
}
}
}Which I thought should work, however it gives the following errors. The program outputs the deletion message as well which is weird so I am not sure what is causing this error.
The code the method is being called in is shown here:
case 2:
printDirectory();
System.out.println("Enter name or number: ");
String nameOrNum = input.nextLine();
deleteEntry(nameOrNum);
break;I have an Entry class which contains information for a single Entry object. Is there a way I could override the equals() method to compare first names and implement the delete method this way? Or can my solution be resolved easily?
Thanks in advance!
Videos
Using Java-8 Collection#removeIf
myList.removeIf(obj -> obj.id == 10);
With Java-7 you'll have to use iterator:
for(Iterator<MyType> iterator = myList.iterator(); iterator.hasNext(); ) {
if(iterator.next().id == 10)
iterator.remove();
}
Note that list iteration is necessary in any case. In Java-8 removeIf method it's just performed internally.
Maybe I don't understand the question but why nobody suggested to use override equals and hashcode for that user class?
class MyObject {
final String id;
final String name;
MyObject(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Objects.equals(id, ((MyObject) o).id);
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "MyObject{id='" + id + "', name='" + name + "'}";
}
}
in this case you can easy remove any object from list
final ArrayList<MyObject> list = new ArrayList<>();
list.add(new MyObject("id1", "name1"));
list.add(new MyObject("id2", "name2"));
list.add(new MyObject("id3", "name3"));
MyObject removeCandidate = new MyObject("id2", "name2");
list.remove(removeCandidate);
System.out.println(list);
code above prints
[MyObject{id='id1', name='name1'}, MyObject{id='id3', name='name3'}]
ArrayList removes objects based on the equals(Object obj) method. So you should implement properly this method. Something like:
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof ArrayTest)) return false;
ArrayTest o = (ArrayTest) obj;
return o.i == this.i;
}
Or
public boolean equals(Object obj) {
if (obj instanceof ArrayTest) {
ArrayTest o = (ArrayTest) obj;
return o.i == this.i;
}
return false;
}
If you are using Java 8 or above:
test.removeIf(t -> t.i == 1);
Java 8 has a removeIf method in the collection interface. For the ArrayList, it has an advanced implementation (order of n).
What you can do it to stream over original list, and leave only objects which satisfy the condition. It might look something like this:
List<Product> filtered = productList.stream()
.filter( p -> p.attributeList().stream().anyMatch( a -> a.attributeId.equals(x))
.collect(Collectors.toList())
in this live we are actually checking if nested list contains at least one object with attributeId = x
p.attributeList().stream().anyMatch( a -> a.attributeId.equals(x)
You can do a foreach loop and remove the unwanted elements. In "product" class you can insert a "FindInnerAtribute" function to search inside the Attributes list and return true if there is some.
List<product> productList = new ArrayList<product>();
for(product p : productList){
if ( p.FindInnerAttribute(x) ){
productList.remove(p);
}
}
How to remove from list
You can use Collection::removeIf(Predicate filter) (available from Java8 onwards), here is a simple example:
final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2));
list.removeIf(value -> value < 2);
System.out.println(list); // outputs "[2]"
You must use an Iterator to iterate and the remove function of the iterator (not of the list) :
Iterator<Pulse> iter = pulseArray.iterator();
while (iter.hasNext()) {
Pulse p = iter.next();
if (p.getCurrent()==null) iter.remove();
}
Note that the Iterator#remove function is said to be optionnal but it is implemented by the ArrayList's iterator.
Here's the code of this concrete function from ArrayList.java :
765 public void remove() {
766 if (lastRet < 0)
767 throw new IllegalStateException();
768 checkForComodification();
769
770 try {
771 ArrayList.this.remove(lastRet);
772 cursor = lastRet;
773 lastRet = -1;
774 expectedModCount = modCount;
775 } catch (IndexOutOfBoundsException ex) {
776 throw new ConcurrentModificationException();
777 }
778 }
779
780 final void checkForComodification() {
781 if (modCount != expectedModCount)
782 throw new ConcurrentModificationException();
783 }
784 }
The expectedModCount = modCount; line is why it won't throw an exception when you use it while iterating.
In your case, there's no need to iterate through the list, because you know which object to delete. You have several options. First you can remove the object by index (so if you know, that the object is the second list element):
a.remove(1); // indexes are zero-based
Or, you can remove the first occurence of your string:
a.remove("acbd"); // removes the first String object that is equal to the
// String represented by this literal
Or, remove all strings with a certain value:
while(a.remove("acbd")) {}
It's a bit more complicated, if you have more complex objects in your collection and want to remove instances, that have a certain property. So that you can't remove them by using remove with an object that is equal to the one you want to delete.
In those case, I usually use a second list to collect all instances that I want to delete and remove them in a second pass:
List<MyBean> deleteCandidates = new ArrayList<>();
List<MyBean> myBeans = getThemFromSomewhere();
// Pass 1 - collect delete candidates
for (MyBean myBean : myBeans) {
if (shallBeDeleted(myBean)) {
deleteCandidates.add(myBean);
}
}
// Pass 2 - delete
for (MyBean deleteCandidate : deleteCandidates) {
myBeans.remove(deleteCandidate);
}
One-liner (java8):
list.removeIf(s -> s.equals("acbd")); // removes all instances, not just the 1st one
(does all the iterating implicitly)
If you change the class Item equals() and compareTo() methods, so that they check only one object field, such as a quantity, it could result in strange behavior in other parts of your application. For example, two items with different itemNo, itemName, and itemPrice, but with the same quantities could be considered equal. Besides, you wouldn't be able to change the comparison attribute without changing the equals() code every time.
Also, creating a custom contains() method makes no sense, since it belongs to the ArrayList class, and not to Item.
If you can use Java 8, a clean way to do it is to use the new Collection's removeIf method:
Suppose you have an Item class with the num and name properties:
class Item {
final int num;
final String name;
Item(int num, String name) {
this.num = num;
this.name = name;
}
}
Given a List<Item> called items and an int variable called number, representing the number of the item you want to remove, you could simply do:
items.removeIf(item -> item.num == number);
If you are unable to use Java 8, you can achieve this by using custom comparators, binary search, and dummy objects.
You can create a custom comparator for each attribute you need to look for. The comparator for num would look like this:
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);
}
}
Then you can use the comparator to sort and search for the desired elements in your list:
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);
}
To search for another field like name, for example, you would need to create a name comparator and use it to sort and run the binary search on your list.
Note this solution has some drawbacks though. Unless you are completely sure that the list didn't change since the last sort, you must re-sort it before running the binarySearch() method. Otherwise, it may not be able to find the correct element. Sorting complexity is O(nlogn), so running it multiple times can get quite expensive depending on the size of your list.
Do you want to remove an object at a specific index? I'm not entirely sure what you mean by 'number field'. If so, jump to method: remove(int):
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove%28int%29
EDIT: If you want to find/adjust a field of an object in the Array list, you can do this (piece of my own code):
public boolean studentHasISBN(ArrayList<Student> st, String s){
for(Student j : st) {
if(s.equals(j.getRentedBookISBN()))
return true;
}
return false;
}
All you have to do is iterate through the list, and search through the field that you want to find. Then use the remove(int) method.
If you don't need to keep a reference to the object you remove, you can just
linkedAccount.removeIf(acc -> acc.getStudentID() == accountNumber);If you want to keep a reference to the element you remove you can
for (Account acc : linkedAccount) { if (acc.getStudentID() == accountNumber) { obj1 = acc; linkedAccount.remove(acc); break; } } // OR for (int i = 0; i < linkedAccount.size(); i++) { if (linkedAccount.get(i).getStudentID() == accountNumber) { obj1 = linkedAccount.remove(i); break; } }Notice that in most case and basiclly an
ArrayListis sufficient When to use LinkedList over ArrayList in Java?
Currently, you're using accountNumber as the index which is incorrect, instead loop over the list and find the index of the object and then remove:
for (int i = 0; i < linkedAccount.size(); i++) {
if (linkedAccount.get(i).getStudentID() == accountNumber) {
obj1 = linkedAccount.remove(i);
break;
}
}
Further, why are you using a LinkedList instead of an ArrayList? the latter is almost always favourable.
To Remove element from the list
objectA.removeIf(x -> conditions);
eg:
objectA.removeIf(x -> blockedWorkerIds.contains(x));
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");
List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");
str1.removeIf(x -> str2.contains(x));
str1.forEach(System.out::println);
OUTPUT: A B C
Although the thread is quite old, still thought to provide solution - using Java8.
Make the use of removeIf function. Time complexity is O(n)
producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));
API reference: removeIf docs
Assumption: producersProcedureActive is a List
NOTE: With this approach you won't be able to get the hold of the deleted item.
As per the JavaDoc:
public boolean remove(Object o)
Removes the first occurrence of the specified element from this list, if it is present. If the list does not contain the element, it is unchanged. More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists). Returns true if this list contained the specified element (or equivalently, if this list changed as a result of the call).
Which essentially means that borrowers.remove(libraryNumber); will work if and only if you have some Borrower object which is equal to that string. Unless you have added an override to the equals method in your Borrower class, it is unlikely that this will ever work. Thus, you have two options:
Override the
equals(and for good practice, thehashcode()) methods within yourBorrowerclass such that two borrower items are considered equal if they have the samelibraryNumber.The second option would be to use an
iteratorto go through yourBorroweritems stored withinborrowerand use the iterator'sremovemethod to delete the objects which have the same property values.
As a side note, although the first approach might be more elegant for some, caution must be taken since in your particular scenario, Borrower objects might not be equal just because they have the same libraryNumber.
public boolean removeBorrower(String libraryNumber)
{
boolean retVal = false;
if(borrowers.contains(libraryNumber))
{
retVal = borrowers.remove(libraryNumber);
}
return retVal;
}
Something like this perhaps? I know it's a long round-about way of doing things, since the easiest way would be
public boolean removeBorrower(String libraryNumber)
{
return borrowers.remove(libraryNumber);
}
But perhaps I don't quite understand what's the problem you're having?