I want to delete duplicate elements and therefore iterate through a ArrayList and compare two consecutive elements. (Persons are comparable)
ArrayList<Person> persons = getHelper().findAllPersons();
Collections.sort(persons);
ListIterator<Person> it = persons.listIterator();
if(it.hasNext()) {
Person tmp = it.next();
while(it.hasNext()) {
if(tmp.getLastDiscovered() == it.next().getLastDiscovered()) {
getHelper().delete(tmp);
}
tmp = it.next();
}
}
I get a NoSuchElementException at tmp = it.next();
Shouldn't the while(it.hasNext()) prevent that?
The problem is you are calling it.next() twice, which will advance the iterator two times.
You should store the value to avoid repeating the side-effect.
Person person = it.next();
if (tmp.getLastDiscovered() == person.getLastDiscovered()) {
getHelper().delete(tmp);
}
tmp = person;
Alternatively, you could use the for-each loop to avoid needing to interact with the iterators (I assume all Person are not null):
Person tmp = null;
for (Person person : persons) {
if (tmp != null && tmp.getLastDiscovered() == person.getLastDiscovered()) {
getHelper().delete(tmp);
}
tmp = person;
}
You're calling it.next() twice (potentially) for each it.hasNext() call, hence your error.
If you want to remove duplicates, why not just populate a TreeSet (providing the appropriate Comparator) with your list ? The semantics of a Set are such that you'll have a distinct set of elements.
If you're using JDK 1.5.0 or later (which you most likely are, since it was released in 2004), you can use a foreach loop to obviate the iterator altogether, greatly simplifying the code.
ArrayList<Person> persons = getHelper().findAllPersons();
Collections.sort(persons);
for (Person person : persons) {
if(tmp.getLastDiscovered() == person.getLastDiscovered()) {
getHelper().delete(tmp);
}
}
while(it.hasNext()) {
if(tmp.getLastDiscovered() == it.next().getLastDiscovered()) {
getHelper().delete(tmp);
}
After that 'while' you are coming to end of the list. Then when it hasn't got next value, you are calling the line below.
tmp = it.next();
That gives you an exception.
Related
I have an ArrayList of objects that have a version number as a field. I want to do some work on that ArrayList, but I only want the most recent version of the object. I was thinking of coding as such:
ArrayList<ObjectVO> ObjectList = getObjectList();
for(ObjectVO myVO : ObjectList) {
Iterator<ObjectVO> iter = ObjectList.iterator();
while(iter.hasNext()) {
ObjectVO checkVO = iter.next();
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
iter.remove();
}
}
}
}
Is this valid? I don't know if the fact that we are in a for loop originally would break the mutability of the ArrayList at runtime.
No, this won't work. iter.remove() will cause the out for loop to fail with ConcurrentModificationException.
Instead of doing this, you can do this with indexed for loops, and a BitSet to keep track of things you want to remove:
BitSet toRemove = new BitSet();
for (int m = 0; m < ObjectList.size(); ++m) {
if (toRemove.get(m)) continue;
ObjectVO myVO = ObjectList.get(m);
for (int c = 0; c < ObjectList.size(); ++c) {
if (toRemove.get(c)) continue;
ObjectVO checkVO = ObjectList.get(c);
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
toRemove.set(c);
}
}
}
}
This is basically your code, but it doesn't do the removal yet. Then you can sweep through the list after and remove them:
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (!toRemove.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
The point of using a BitSet like this is that removal from an ArrayList is inefficient if you are removing from anywhere other than the end, because it requires all of the elements "to the right" of the element you remove to be shuffled along by one position. The loop with the set/get and clear allows you to only move each of the retained elements once.
You can do a bit better than the quadratic loop, though, if you group the list elements by things with the same ID: then you don't need to keep on checking the entire list:
BitSet toKeep = new BitSet();
IntStream.range(0, ObjectList.size())
.mapToObj(a -> a)
.collect(
groupingBy(a -> ObjectList.get(a).getID(),
maxBy(comparingInt(a -> ObjectList.get(a).getVersion()))))
.values()
.forEach(a -> toKeep.set(a));
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (toKeep.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
Assuming you have the memory, rather than do an O(N^2) operation, you could do this more efficiently (O(N)) by using a Map to track the newest Version for each Id. One pass tracks the newest version for each Id, and the second removes elements which are not the latest.
Map<Integer, Thing> newestById = new HashMap<>();
for (Thing thing : list) {
newestById.merge(thing.id, thing, (a,b) -> a.version > b.version ? a : b);
}
list.removeIf(thing -> thing != newestById.get(thing.id)); }
Depending on your use case, you might even be able to store your data in a Map instead of a List, and check if the version is the latest before adding it to the Map.
As the other answers have discussed this won't work. You have three options as I see them, trading memory for CPU cycles/flexibility. I've used Integer instead of ObjectVO in my examples, but it'll be trivial to swap them.
Option 1 - moderate memory, single-pass of the array
Track the highest ID you've seen and populate an ArrayList with new items as they meet the criteria. When you encounter a new higher ID, throw away the ArrayList and create a new one:
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
ArrayList<Integer> allObjectsMatchingId = new ArrayList<>();
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
allObjectsMatchingId = new ArrayList<>();
} else if(currentObject == bestId) {
allObjectsMatchingId.add(currentObject);
}
}
return allObjectsMatchingId;
Option 2 - more expensive memory, single-pass of the array, most flexible.
For each ID you see, create an ArrayList and store it against a map. This allows you to easily change the criteria about what ID you want to keep.
ArrayList<Integer> objectList = getObjectList();
Map<Integer, ArrayList<Integer>> objectsById = new HashMap<>();
for(Integer currentObject : objectList) {
ArrayList<Integer> listForId = objectsById.get(currentObject);
if(listForId == null) {
listForId = new ArrayList<Integer>();
}
listForId.add(currentObject);
objectsById.put(currentObject, listForId);
}
Integer bestId = -1;
for(Integer i : objectsById.keySet()) {
if(i > bestId) {
bestId = i;
}
}
return objectsById.get(bestId);
Option 3 - no additional memory aside from id, two-passes of the array.
Search through the ArrayList for the highest ID, then filter the array to only elements that pass that filter.
This is the closest to your current implementation, the difference being that you do them in separate steps. This reduces complexity from O(N^2) to O(N), and is valid as you aren't modifying the ArrayList while iterating it. You could use a Stream here to filter instead of an iterator if you're Java 8 compatible. See Java: Efficient ArrayList filtering?
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
}
}
Iterator<Integer> iter = objectList.iterator();
while(iter.hasNext()) {
if(iter.next() != bestId) {
iter.remove();
}
}
Why not use Java Streams to solve this:
Collection<ObjectVO> result = objectList.stream()
.collect(Collectors.toMap(ObjectVO::getID, Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(ObjectVO::getVersion))))
.values();
This creates a map which contains the max version for each id. Then you can just use Map.values() to get the object list.
If you need a List or an ArrayList you can just use new ArrayList<>(result).
I am using myBatis 3.2.x and have run into a scenario where I need to do multiple table inserts in one database trip,
I was wondering if I can create a master INSERT sql mapper file which would call these multi table inserts and save me network trips
I am consuming JSON objects from a EMS server and my Turn around time is a bit higher then required.
All suggestions and hints are welcome.
Thanks
VR
Use Collections.sort() to sort and use a simple for cycle to catch doubles, e.g.:
Collections.sort(myList);
A previous = null;
for (A elem: myList) {
if (elem.compareTo(previous) == 0) {
System.err.println("Duplicate: "+elem);
}
previous = elem;
}
Assuming that the Comparable is consistent with the equals implementation, you can use a Set. You can add each element to a Set using Set.add(..) and use the return value of add to determine if the value was already present in the Set and create either a Set or a List to return.
Note: If you need each duplicate returned only once, you can change the return list to a set.
List<A> duplicates(List<A> myList) {
Set<A> s = new HashSet<A>();
List<A> duplicates = new ArrayList<A>(); // change to using a Set if you want to report each duplicate item only once.
for (A item: myList) {
if (!s.add(item)) {
duplicates.add(item);
}
}
return duplicates;
}
An improved version using sorting (to report duplicate elements only once, I assume there are no null values in the list):
Collections.sort(myList);
A previous = null, elem = null;
for (java.util.Iterator<A> it = myList.iterator; it.hasNext(); elem = it.next()) {
if (elem.compareTo(previous) == 0) {
System.err.println("Duplicate: "+elem);
while (it.hasNext() && (elem = it.next()).compareTo(previous)) {
//loop through other values
}
}
previous = elem;
}
A version using SortedSet (probably this is faster a bit): and corrected the same
SortedSet<A> set = new TreeSet<>(), duplicates = new TreeSet<>();
for (A a: myList) {
if (!set.add(a)) {
duplicates.add(a);
}
}
return duplicates;//or for (A a: duplicates) System.println("Duplicate: " + a);
I executing below code but some times i got java.util.ConcurrentModificationException exception..But some times working fine.please let me know where i did wrong code.Below is my code please check my logic also if there is any better way then let me know.
public String saveSkills(HttpServletRequest request,#RequestParam String skills,#RequestParam String Email) throws IOException
{
Domain domain1 = (Domain)request.getSession().getAttribute("Domain");
Long domanId =domain1.getDomainId();
System.out.println(skills);
String[] skillsParts = skills.split(",");
UserProfile user = userProfileManager.getUserByEmail(domain1.getPrimary_Domain_Id(), Email);
if(user.getSkillsList().size()>0){
Iterator it = user.getSkillsList().iterator();
while (it.hasNext())
{
Skills skillsitereator = (Skills) it.next();
int count=0;
for(int i =0;i<skillsParts.length;i++){
if((skillsParts)[i].equals(skillsitereator.getSkillName())){
break;
}else{
count++;
}
}
if(count == skillsParts.length){
it.remove();
userProfileManager.update(user);
}
}
}else{
for(int i =0;i<skillsParts.length;i++){
Skills skillObj = new Skills();
skillObj.setSkillName(skillsParts[i]);
user.getSkillsList().add(skillObj);
}
userProfileManager.update(user);
}
skillsParts = skills.split(",");
System.out.println(skillsParts);
ArrayList<Integer> values =new ArrayList<Integer>();
for(int i =0;i<skillsParts.length;i++){
Iterator it = user.getSkillsList().iterator();
while (it.hasNext())
{
Skills skillsitereator = (Skills) it.next();
if((skillsParts)[i].trim().equals(skillsitereator.getSkillName().trim())){
break;
}
else{
Skills skillObj = new Skills();
skillObj.setSkillName(skillsParts[i]);
user.getSkillsList().add(skillObj);
userProfileManager.update(user);
}
}
}
Gson gson = new Gson();
return gson.toJson(user);
}
This is from the JavaDoc for ConcurrentModificationException:
For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
In your last loop, you sometimes do
user.getSkillsList().add(skillObj);
while iterating using user.getSkillsList().iterator().
ConcurrentModificationExceptions happen when modifying a Collection while iterating it, other than using the Iterator.remove() method.
So, it will be thrown when executing:
user.getSkillsList().add(skillObj);
From the Java Tutorials, The Collection interface :
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
I have added data into ArrayList and now want to update that list be deleting some element from it.
I have element something like 1,2,3,4 in ArrayList of type CartEntry.
Code :
ArrayList<CartEntry> items = new ArrayList<CartEntry>();
public void remove(int pId)
{
System.out.println(items.size());
for(CartEntry ce : items)
{
if(ce.getpId() == pId)
{
items.remove(ce);
//System.out.println(items.get(1));
}
}
items.add(new CartEntry(pId));
}
CartEntry Code :
public long getpId() {
return pId;
}
Constructor :
public CartEntry(long pId) {
super();
this.pId = pId;
}
when I am trying this code it gives me an error:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
Here pId is the argument that specify that item should be deleted from items.
Suppose I want to delete item that have 2 data then what will I have to do ?
You are facing ConcurrentModificationException because you are doing two operations on the same list at a time. i.e looping and removing same time.
Inorder to avoid this situation use Iterator,which guarantees you to remove the element from list safely .
A simple example looks like
Iterator<CartEntry> it = list.iterator();
while (it.hasNext()) {
if (it.next().getpId() == pId) {
it.remove();
break;
}
}
There are at least two problems with your code:
you call remove on the collection you iterate over, that will cause a ConcurrentModificationException if you continue iterating after the remove.
There are two ways to fix this:
stop iterating after you found the object you want to remove (just add a break or a return) or
switch from the enhanced for-loop to using an Iterator and its remove method.
you add an element in your remove method, that's probably not what you want.
So I'd use this code (this assumes that there is only ever one CartEntry with a given id in the list):
public void remove(int pId)
{
for(CartEntry ce : items)
{
if(ce.getpId() == pId)
{
items.remove(ce);
return;
}
}
}
If the assumption with the unique id is not correct, then you'll need to use the Iterator approach:
public void remove(int pId)
{
Iterator<CartEntry> it = items.iterator();
while(it.hasNext())
{
CartEntry ce = it.next();
if(ce.getpId() == pId)
{
it.remove();
}
}
}
you have created an Arraylist of type carEntry. So you need to create an Iterator of type CarEntry
Iterator<CarEntry> it = items.iterator();
while(it.hasNext())
{
if(it.next().getPId == PId)
it.remove();
}
Implement .equals in CartEntry and then use ArrayList.remove(CartEntry) or loop through your array list, find the item with some condition, mark the index, and call ArrayList.remove(index) -- AFTER the loop
Try,
public void remove(int pId){
Iterator<CartEntry> it = items.iterator();
while(it.hasNext()) {
CartEntry entry = it.next();
if (entry.getpId() == pId) {
it.remove();
}
}
}
The enhanced-for(or for each) loop for iterating over an Expression which is a subtype of Iterable<E> or raw Iterable, basically equivalent to the following form:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableIdentifiers_opt TargetType Identifier = (TargetType) #i.next();
Statement
}
This is clearly stated in jls 14.14.2. The enhanced for statement section.
For your context the Expression is an ArrayList. the iterators returned by ArrayList's iterator method is fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
use an Iterator instead and use it's own remove() method:
Iterator<E>iterator = list.iterator();
while(iterator.hasNext())
if(iterator.next().equals(E))
iterator.remove();
I was just wondering what the easiest way to iterate over a set indefinitely, i.e. when it reaches the end it next(); calls the first object. I'm assuming that this is not an already predefined function in Java, so just looking for the easiest way to implement this in Java.
There's a method in the excellent Google Collections library which does this:
Set<String> names = ...;
Iterable<String> infinite = Iterables.cycle(names);
(I can't recommend the Google Collections library strongly enough. It rocks very hard. I'm biased as I work for Google, but I think pretty much every Googler writing Java would tell you how useful the collections are.)
Iterator it = mylist.iterator();
while (it.hasNext())
{
MyType t = (MyType)it.next();
// do something
if (!it.hasNext())
it = mylist.iterator();
}
Try EndlessIterator from Cactoos:
Iterator<String> names = new EndlessIterator<>("John");
It will always return "John" and will never end.
Also, check EndlessIterable, which implements Iterable and does the same.
If you're making the iterator, in the next method you can have an if condition that checks if there's another object in the list. If there is, then you return that object, if there isn't then you go back to the start of the list and return that object.
This is what I can think of...
iterator = set.getIterator
//other code
if (iterator.hasNext())
//do code here
else
iterator = set.getIterator();
How about ?
List<String> list = // ArraysList
Interator<String> it = null;
while(true) {
it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
If you don't want to use Guava but still want a reusable solution:
public static class CyclicIterator<E, C extends Collection<E>> implements Iterator<E> {
final private C mElements;
private Iterator<E> mIterator;
public CyclicIterator(C elements) {
mElements = elements;
mIterator = elements.iterator();
}
#Override
public boolean hasNext() {
if (! mIterator.hasNext()) {
mIterator = mElements.iterator();
}
return mIterator.hasNext();
}
#Override
public E next() {
if (! mIterator.hasNext()) {
mIterator = mElements.iterator();
}
return mIterator.next();
}
}
Note: this doesn't support the remove() method but it could easily be added if needed. Also it's not thread safe.
I think what you want never help You can do anything with your iterator that's easy but you must be carefull with any new thing you add im not used with this style but this is what you want though :
if (! It.hasNext() )
{
while ( It.hasPrevious() )
{
It = It.Previous();
}
} else {
It = It.Next();
}
This way is nothing if your really interested you should instead make next pointer of the last to the first always when pushing a new list.
std jdk:
Iterable<String> infinite = Stream.generate(names.stream()).flatMap(e -> e).iterator()