Iterating over sets of sets - java

I am attempting to write a program that iterates over a set of sets. In the example code below, I am getting an error that stating that iter.next() is of type object rather than a set of strings. I am having some other more mysterious issues with iterating over sets of sets as well. Any suggestions?
Set<String> dogs= new HashSet<String>();
dogs.add("Irish Setter");
dogs.add("Poodle");
dogs.add("Pug");
dogs.add("Beagle");
Set<String> cats = new HashSet<String>();
cats.add("Himalayan");
cats.add("Persian");
Set<Set<String>> allAnimals = new HashSet<Set<String>>();
allAnimals.add(cats);
allAnimals.add(dogs);
Iterator iter = allAnimals.iterator();
System.out.println(allAnimals.size());
while (iter.hasNext())
{
System.out.println(iter.next().size());
}
A related question with the same setup (minus the loop).
The code fragment below results in a final output that includes tildes. But I don't want to change allAnimals as I go! How can I edit extension without affecting the larger set (allAnimals).
for (Set<String> extension : allAnimals)
{
System.out.println("Set size: " + extension.size());
extension.add("~");
System.out.println(extension);
}
System.out.println(allAnimals);

Your allAnimals variable is of type Set<Set<String>>, however, when you ask its Iterator you "forget" the type information. According to the compiler, your iterator just contains Objects. Change the line where you get the Iterator to this
Iterator<Set<String>> iter = allAnimals.iterator();
and all should be fine.

Use an enhanced for loop for traversing the sets, is easier than using an iterator:
for (Set<String> names : allAnimals) {
System.out.println(names.size());
}
For example, to traverse all the animal's names:
for (Set<String> names : allAnimals) {
for (String name : names) {
System.out.println(name);
}
}

You do not mention the type on which your iterator is defined. So as far as it is concerned it expects an object as next.

I would just use a (nested) foreach loop:
for(Set<String> animals : allAnimals) {
int size = animals.size(); // if you want it
for (String animal : animals) {
// do something with the name
}
}

Related

Remove a value from a List nested in a Map

I've got a HashMap which contains an ArrayList as value. I want to check if one of the lists contains an object and remove that object from the list. How can I achieve that?
I've tried using some for loops, but then I get a ConcurrentModificationException. I can't get that exception away.
My hashmap:
Map<String,List<UUID>> inAreaMap = new HashMap<String, ArrayList<UUID>>();
I intend to check if the ArrayList contains the UUID I've got, and if so, I want to remove it from that ArrayList. But I don't know the String at that position of the code.
What I already tried:
for (List<UUID> uuidlist : inAreaMap.values()) {
for (UUID uuid : uuidlist) {
if (uuid.equals(e.getPlayer().getUniqueId())) {
for (String row : inAreaMap.keySet()) {
if (inAreaMap.get(row).equals(uuidlist)) {
inAreaMap.get(row).remove(uuid);
}
}
}
}
}
There is a more elegant way to do this, using Java 8:
Map<String, ArrayList<UUID>> map = ...
UUID testId = ...
// defined elsewhere
// iterate through the set of elements in the map, produce a string and list for each
map.forEach((string, list) -> {
// as the name suggests, removes if the UUID equals the test UUID
list.removeIf(uuid -> uuid.equals(testId));
});
try with the iterator.
inareamap.iterator().. and.. iterator.remove()
If you have Java 8, the solution of camaron1024's solution is the best. Otherwise you can make use of the fact that you have a list and iterate through it backwards by index.
for(ArrayList<UUID> uuidlist : inareamap.values()) {
for(int i=uuidlist.size()-1;i>=0;i--) {
if (uuidlist.get(i).equals(e.getPlayer().getUniqueId()))
uuidlist.remove(i);
}
}
Here the easy solution.
UUID key = ... ;
for(Map.Entry<String,ArrayList<UUID>> e : hm.entrySet()){
Iterator<UUID> itr = e.getValue().iterator();
while(itr.hasNext()){
if(itr.next() == key)
itr.remove();
}
}

change a list while iterating or using a for each loop

I am trying to iterate (or use a for each loop) on a Linked list class and be able to change the item (when found) to a passed in parameter.
for(Item n : items)
{
if (n.getKey().equals(key))
{
n = new Item(key, value);
}
}
Does this change of data work or is it temporary (only to be lost when the activation record is deleted)?
You can't iterate over a collection and modify it. You will always get a java.util.ConcurrentModificationException. First off all you need to use an iterator, to remove the item. Then you can use a second list to store the data you want to add.
Here you are an example:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("This");
linkedList.add("is");
linkedList.add("an");
linkedList.add("test");
LinkedList<String> temp = new LinkedList<String>();
for (Iterator<String> iterator = linkedList.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
if(string.equals("an")) {
iterator.remove();
temp.add("a");
}
}
linkedList.addAll(temp);
You can call iterator.remove() to savely remove the current item from list.
You are using fast enumeration, which protects the list that you are iterating through. If you would like to change the data in the list, you would need to use a traditional for loop.
Basically how fast enumeration works is it makes the array read-only in the block of code because you have no access to what integer the iteration is.
You could do this:
for(int i = 0; i < items.length; i++)
{
if (n.getKey().equals(key))
{
items[i] = new Item(key, value);
}
}

How to remove multiple elements in Vector in Java?

I read from .txt file all of the ids and insert these ids into Vector.
String pathSelectedfile = fileChooser.getSelectedFile().getAbsolutePath();
File selectedFile = new File(pathSelectedfile);
Scanner readFile = new Scanner(selectedFile);
Vector ids=new Vector();
while (readFile.hasNextLine()) {
String id= readFile.nextLine();
ids.addElement(id);
}
then I want to remove multiple ids in Vector.i can do that by for loop
but information is too big.tnx a lot
To remove multiple values
Vector vector = new Vector();
vector.add("value1");
vector.add("value2");
vector.add("value3");
vector.add("value4");
System.out.println("Size : "+vector.size());
// to remove single value
vector.remove("value1");
System.out.println("Size : "+vector.size());
Vector itemsToRemove = new Vector();
itemsToRemove.add("value3");
itemsToRemove.add("value4");
//remove multiple values
vector.removeAll(itemsToRemove);
System.out.println("Size : "+vector.size());
//to remove all elements
vector.removeAllElements();
// or
vector.clear();
But instead of using Vector consider to use ArrayList since Vector is obsolete collection.
Read this : Why is Java Vector class considered obsolete or deprecated?
Also use generics Like ArrayList<String> idList = new ArrayList() if you store only String elements in list.
If you want to skip duplicates when adding elements in Vector, use the following code
Vector vector = new Vector() {
#Override
public synchronized boolean add(Object e) {
if(!contains(e)){
return super.add(e);
}
System.out.println("Element " + e +" is duplicate");
return false ;
}
};
But if you want to add only unique elements, use Set
Do completely remove the duplicated ids, you could use the following:
Set<String> ids=new LinkedHashSet<String>();
Set<String> duplicates=new HashSet<String>();
while (readFile.hasNextLine()) {
String id= readFile.nextLine();
if(!ids.add(id)) {
duplicates.add(id);
}
}
ids.removeAll(duplicates)
Note that unlike Vector, LinkedHashSet is not synchronized. In most cases this is not a bad thing, but in the case that you actually need it to be synchronized, wrap it using Collections.synchronizedSet()
READ the javadoc and pay attention to methods starting with remove http://docs.oracle.com/javase/6/docs/api/java/util/Vector.html. This should be you first approach not SO.
If you "want to remove multiple ids in Vector" do the following
ids = new Vector(new HashSet(ids))

removing duplicates from list of lists and preserving lists

I have an arrayList of arrayLists. Each inner arraylist contains some objects with the format (name.version) .
{ {a.1,b.2,c.3} , {a.2,d.1,e.1} , {b.3,f.1,z.1}....}
For example a.1 implies name = a and version is 1.
So i want to eliminate duplicates in this arraylist of lists. For me , two objects are duplicate when they have the same name
So essentially my output should be
{ { a.1,b.2,c.3},{d.1,e.1} ,{f.1 ,z.1} }
Note that i want the output in the exact same form (That is , i dont want a single list with no duplicates)
Can someone provide me with an optimal solution for this?
I can loop through each inner list and place the contents in the hashset. But two issues there, i cant get back the answer in
form of list of lists.Another issue is that when i need to override equals for that object , but i am not sure if that would
break other code. These objects are meaningfully equal if their names are same (only in this case. I am not sure that would
cover the entire spectrum)
Thanks
I used Iterator.remove() to modify the collection as you move through it.
// build your example input as ArrayList<ArrayList<String>>
String[][] tmp = { { "a.1", "b.2", "c.3" }, { "a.2", "d.1", "e.1" },
{ "b.3", "f.1", "z.1" } };
List<List<String>> test = new ArrayList<List<String>>();
for (String[] array : tmp) {
test.add(new ArrayList<String>(Arrays.asList(array)));
}
// keep track of elements we've already seen
Set<String> nameCache = new HashSet<String>();
// iterate and remove if seen before
for (List<String> list : test) {
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String element = it.next();
String name = element.split("\\.")[0];
if (nameCache.contains(name)) {
it.remove();
} else {
nameCache.add(name);
}
}
}
System.out.println(test);
Output
[[a.1, b.2, c.3], [d.1, e.1], [f.1, z.1]]
List<List<Pair>> inputs; // in whatever format you have them
List<List<Pair>> uniqued = new ArrayList<>(); // output to here
Set<String> seen = new HashSet<String>();
for (List<Pair> list : inputs) {
List<Pair> output = new ArrayList<>();
for (Pair p : list)
if (seen.add(p.getName()))
output.add(p);
uniqued.add(output);
}
Create a Set. Iterate over the list of lists' items. See if the item is in the Set. If it is already there, ignore it. If it isn't, add it to the Set and the list of lists.
Your method will return a new list of lists, not modify the old one. Modifying a list while iterating over it is a pain.

How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList

I have an ArrayList that I want to iterate over. While iterating over it I have to remove elements at the same time. Obviously this throws a java.util.ConcurrentModificationException.
What is the best practice to handle this problem? Should I clone the list first?
I remove the elements not in the loop itself but another part of the code.
My code looks like this:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething might call Test.removeA();
Two options:
Create a list of values you wish to remove, adding to that list within the loop, then call originalList.removeAll(valuesToRemove) at the end
Use the remove() method on the iterator itself. Note that this means you can't use the enhanced for loop.
As an example of the second option, removing any strings with a length greater than 5 from a list:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
From the JavaDocs of the ArrayList
The iterators returned by this class's iterator and listIterator
methods are 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.
You are trying to remove value from list in advanced "for loop", which is not possible, even if you apply any trick (which you did in your code).
Better way is to code iterator level as other advised here.
I wonder how people have not suggested traditional for loop approach.
for( int i = 0; i < lStringList.size(); i++ )
{
String lValue = lStringList.get( i );
if(lValue.equals("_Not_Required"))
{
lStringList.remove(lValue);
i--;
}
}
This works as well.
In Java 8 you can use the Collection Interface and do this by calling the removeIf method:
yourList.removeIf((A a) -> a.value == 2);
More information can be found here
You should really just iterate back the array in the traditional way
Every time you remove an element from the list, the elements after will be push forward. As long as you don't change elements other than the iterating one, the following code should work.
public class Test(){
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff(){
for(int i = (abc.size() - 1); i >= 0; i--)
abc.get(i).doSomething();
}
public void removeA(A a){
abc.remove(a);
}
}
While iterating the list, if you want to remove the element is possible. Let see below my examples,
ArrayList<String> names = new ArrayList<String>();
names.add("abc");
names.add("def");
names.add("ghi");
names.add("xyz");
I have the above names of Array list. And i want to remove the "def" name from the above list,
for(String name : names){
if(name.equals("def")){
names.remove("def");
}
}
The above code throws the ConcurrentModificationException exception because you are modifying the list while iterating.
So, to remove the "def" name from Arraylist by doing this way,
Iterator<String> itr = names.iterator();
while(itr.hasNext()){
String name = itr.next();
if(name.equals("def")){
itr.remove();
}
}
The above code, through iterator we can remove the "def" name from the Arraylist and try to print the array, you would be see the below output.
Output : [abc, ghi, xyz]
Do the loop in the normal way, the java.util.ConcurrentModificationException is an error related to the elements that are accessed.
So try:
for(int i = 0; i < list.size(); i++){
lista.get(i).action();
}
Here is an example where I use a different list to add the objects for removal, then afterwards I use stream.foreach to remove elements from original list :
private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
long diff;
long diffSeconds;
List<Object> objectsToRemove = new ArrayList<>();
for(CustomerTableEntry item: customersTableViewItems) {
diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
diffSeconds = diff / 1000 % 60;
if(diffSeconds > 10) {
// Element has been idle for too long, meaning no communication, hence remove it
System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
objectsToRemove.add(item);
}
}
objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}
One option is to modify the removeA method to this -
public void removeA(A a,Iterator<A> iterator) {
iterator.remove(a);
}
But this would mean your doSomething() should be able to pass the iterator to the remove method. Not a very good idea.
Can you do this in two step approach :
In the first loop when you iterate over the list , instead of removing the selected elements , mark them as to be deleted. For this , you may simply copy these elements ( shallow copy ) into another List.
Then , once your iteration is done , simply do a removeAll from the first list all elements in the second list.
In my case, the accepted answer is not working, It stops Exception but it causes some inconsistency in my List. The following solution is perfectly working for me.
List<String> list = new ArrayList<>();
List<String> itemsToRemove = new ArrayList<>();
for (String value: list) {
if (value.length() > 5) { // your condition
itemsToRemove.add(value);
}
}
list.removeAll(itemsToRemove);
In this code, I have added the items to remove, in another list and then used list.removeAll method to remove all required items.
Instead of using For each loop, use normal for loop. for example,the below code removes all the element in the array list without giving java.util.ConcurrentModificationException. You can modify the condition in the loop according to your use case.
for(int i=0; i<abc.size(); i++) {
e.remove(i);
}
Sometimes old school is best. Just go for a simple for loop but make sure you start at the end of the list otherwise as you remove items you will get out of sync with your index.
List<String> list = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
if ("removeMe".equals(list.get(i))) {
list.remove(i);
}
}
You can also use CopyOnWriteArrayList instead of an ArrayList. This is the latest recommended approach by from JDK 1.5 onwards.
Do somehting simple like this:
for (Object object: (ArrayList<String>) list.clone()) {
list.remove(object);
}
An alternative Java 8 solution using stream:
theList = theList.stream()
.filter(element -> !shouldBeRemoved(element))
.collect(Collectors.toList());
In Java 7 you can use Guava instead:
theList = FluentIterable.from(theList)
.filter(new Predicate<String>() {
#Override
public boolean apply(String element) {
return !shouldBeRemoved(element);
}
})
.toImmutableList();
Note, that the Guava example results in an immutable list which may or may not be what you want.
for (A a : new ArrayList<>(abc)) {
a.doSomething();
abc.remove(a);
}
"Should I clone the list first?"
That will be the easiest solution, remove from the clone, and copy the clone back after removal.
An example from my rummikub game:
SuppressWarnings("unchecked")
public void removeStones() {
ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
// remove the stones moved to the table
for (Stone stone : stones) {
if (stone.isOnTable()) {
clone.remove(stone);
}
}
stones = (ArrayList<Stone>) clone.clone();
sortStones();
}
I arrive late I know but I answer this because I think this solution is simple and elegant:
List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();
public void fillingList() {
listFixed.add("Andrea");
listFixed.add("Susana");
listFixed.add("Oscar");
listFixed.add("Valeria");
listFixed.add("Kathy");
listFixed.add("Laura");
listFixed.add("Ana");
listFixed.add("Becker");
listFixed.add("Abraham");
dynamicList.addAll(listFixed);
}
public void updatingListFixed() {
for (String newList : dynamicList) {
if (!listFixed.contains(newList)) {
listFixed.add(newList);
}
}
//this is for add elements if you want eraser also
String removeRegister="";
for (String fixedList : listFixed) {
if (!dynamicList.contains(fixedList)) {
removeResgister = fixedList;
}
}
fixedList.remove(removeRegister);
}
All this is for updating from one list to other and you can make all from just one list
and in method updating you check both list and can eraser or add elements betwen list.
This means both list always it same size
Use Iterator instead of Array List
Have a set be converted to iterator with type match
And move to the next element and remove
Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) {
itr.next();
itr.remove();
}
Moving to the next is important here as it should take the index to remove element.
List<String> list1 = new ArrayList<>();
list1.addAll(OriginalList);
List<String> list2 = new ArrayList<>();
list2.addAll(OriginalList);
This is also an option.
If your goal is to remove all elements from the list, you can iterate over each item, and then call:
list.clear()
What about of
import java.util.Collections;
List<A> abc = Collections.synchronizedList(new ArrayList<>());
ERROR
There was a mistake when I added to the same list from where I took elements:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
for (i in this) {
this.add(_fun(i)) <--- ERROR
}
return this <--- ERROR
}
DECISION
Works great when adding to a new list:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
val newList = mutableListOf<T>() <--- DECISION
for (i in this) {
newList.add(_fun(i)) <--- DECISION
}
return newList <--- DECISION
}
Just add a break after your ArrayList.remove(A) statement

Categories