This question already has answers here:
Java, Using Iterator to search an ArrayList and delete matching objects
(1 answer)
How do I compare strings in Java?
(23 answers)
Closed 10 years ago.
I have class with ArrayList of teams and i want remove team which name is "FREE";
so i tried:
public void removeFree()
{
for (int i = 0 ; i < numberOfTeams ; i++ )
{
if (this.getListOfTeams().get(i).getName() == "FREE")
{
this.getListOfTeams().remove(i);
}
else
{}
}
}
That makes my app crash.
Use, equals() method to check if two strings are meaningfully equal. == operator just checks if two reference variables refer to the same object.
if (this.getListOfTeams().get(i).getName() == "FREE")
should be
if (this.getListOfTeams().get(i).getName().equals("FREE"))
Also to add more, even if you use equals() you'd get ConcurrentModificationException as you are removing the elements from the arrayList while iterating over it. you have to use an iterator and remove elements from it rather.
Iterator<Team> itr = getListOfTeams.iterator();
while(itr.hasNext()){
if (itr.next().getName().equals("FREE"))
{
itr.remove();
}
else
{}
}
}
To remove an element from a List while iterating it, it's safer to use an Iterator along with the remove method:
for (Iterator it = getListOfTeams().iterator;it.hasNext();) {
String name = it.next();
if ("FREE".equals(name) {
it.remove();
}
else{}
}
Please note how String value comparison in Java should usually be done by means of the String.equals() method. == is the reference equality operator. See How do I compare strings in Java?
You are trying to remove an item while you are looping the same ArrayList. You need to clone first, iterate the cloned list and then delete the items of the first pointer.
so consider this:
List<Object> arrayToIterate = getListOfTeams().clone();
for (int i = 0 ; i < numberOfTeams ; i++ )
{
if (tarrayToIterate.get(i).getName().equals("FREE"))
{
this.getListOfTeams().remove(i);
}
else
{}
}
Also you are comparing an string with == instead of equals.
Related
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 2 years ago.
I wrote the following code:
for (Character currentChar : userDocuments.keySet()) {
List<QueryDocumentSnapshot> currentList = userDocuments.get(currentChar);
if (currentList == null) {
userDocuments.remove(currentChar);
continue;
}
for (int index = 0; index < currentList.size(); ++index) {
final String currentFullName = currentList.get(index).getString("full_name");
if (currentFullName == null || !(searchText.contains(currentFullName))) {
currentList.remove(index);
}
}
if (currentList.size() == 0) {
userDocuments.remove(currentChar);
}
}
I want to iterate over a map Map<Character,List<QueryDocumentSnapshot>> check if the full_name (field of each QueryDocumentSnapshot) contains searchText and if it's not, remove this element from the list. In case list is empty, remove the entire list. But for some reason I get java.util.ConcurrentModificationException on the first line. Also, how can I use contains without case sensitive?
The ConcurrentModificationException occurs when an object is tried to be modified concurrently when it is not permissible. This exception usually comes when one is working with Java Collection classes. For Example - It is not permissible for a thread to modify a Collection when some other thread is iterating over it.
In your case, it is arising coz you are trying to remove some elements from both the Map and ArrayList while iterating over them.
You can avoid it using:
Iterator<Map.Entry<Character, List<QueryDocumentSnapshot>>> mapIterator = userDocuments.entrySet().iterator();
while (mapIterator.hasNext())
{
Map.Entry<Character,List<QueryDocumentSnapshot>> entry = mapIterator.next();
List<QueryDocumentSnapshot> currentList = entry.getValue();
if (currentList == null) {
mapIterator.remove();
continue;
}
Iterator<QueryDocumentSnapshot> listIterator = currentList.iterator();
while (listIterator.hasNext()) {
final String currentFullName = listIterator.next().getString("full_name");
if (currentFullName == null || !(searchText.contains(currentFullName))){
listIterator.remove();
}
}
if (currentList.size() == 0) {
mapIterator.remove();
}
}
And to answer your question 'how can I use contains without case sensitive' , you can simply use something like this:
searchText.toLowerCase().contains(currentFullName.toLowerCase())
Given the following datatype Testcase (XQuery, Testpath, FirstInputFile, SecondInputFile, Expected)
how can I properly delete duplicates.
Definition of duplicates:
If FirstInputFile already in the list as SecondInputFile vice versa.
Here is the Testdata
tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL", "FAIL2", "FAILED"));
tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL2", "FAIL", "FAILED"));
tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL4", "FAIL3", "FAILED2"));
tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL3", "FAIL4", "FAILED2"));
and here is the function
protected void deleteExistingDuplicatesInArrayList(final ArrayList<HeaderAndBodyTestcase> list) {
for (int idx = 0; idx < list.size() - 1; idx++) {
if (list.get(idx).firstInputFile.equals(list.get(idx).secondInputFile)
|| (list.get(idx + 1).firstInputFile.equals(list.get(idx).firstInputFile)
&& list.get(idx).secondInputFile.equals(list.get(idx + 1).secondInputFile)
|| (list.get(idx).firstInputFile.equals(list.get(idx + 1).secondInputFile)
&& list.get(idx).secondInputFile.equals(list.get(idx + 1).firstInputFile)))) {
list.remove(idx);
}
}
}
This solution is already working, but seems very crappy, so is there a better solution to this?
put everything in a Set using a comparator if necessary, and create a list from this set if you really need a List (and not a Collection)
Set<HeaderAndBodyTestcase> set = new Hashset<>(list);
Given your rather peculiar "equality" constraints, I think the best way would be to maintain two sets of already seen first- and second input files and a loop:
Set<String> first = new HashSet<>();
Set<String> second = new HashSet<>();
for (HeaderAndBodyTestcase tc : tcs) {
if (! first.contains(tc.getSecondInputFile()) &&
! second.contains(tc.getFirstInputFile())) {
first.add(tc.getFirstInputFile());
second.add(tc.getSecondInputFile());
System.out.println(tc); // or add to result list
}
}
This will also work if "equal" elements do not appear right after each other in the original list.
Also note that removing elements from a list while iterating the same list, while working sometimes, will often yield unexpected results. Better create a new, filtered list, or if you have to remove, create an Iterator from that list and use it's remove method.
On closer inspections (yes, it took me that long to understand your code), the conditions in your current working code are in fact much different than what I understood from your question, namely:
remove element if first and second is the same (actually never checked for the last element in the list)
remove element if first is the same as first on last, and second the same as second on last
remove if first is same as last second and vice versa
only consider consecutive elements (from comments)
Given those constraints, the sets are not needed and also would not work properly considering that both the elements have to match (either 'straight' or 'crossed'). Instead you can use pretty much your code as-is, but I would still use an Iterator and keep track of the last element, and also split the different checks to make the whole code much easier to understand.
HeaderAndBodyTestcase last = null;
for (Iterator<HeaderAndBodyTestcase> iter = list.iterator(); iter.hasNext();) {
HeaderAndBodyTestcase curr = iter.next();
if (curr.firstInputFile.equals(curr.secondInputFile)) {
iter.remove();
}
if (last != null) {
boolean bothEqual = curr.firstInputFile.equals(last.firstInputFile)
&& curr.secondInputFile.equals(last.secondInputFile);
boolean crossedEqual = curr.secondInputFile.equals(last.firstInputFile)
&& curr.firstInputFile.equals(last.secondInputFile);
if (bothEqual || crossedEqual) {
iter.remove();
}
}
last = curr;
}
This question already has answers here:
Remove duplicates from a list of objects based on property in Java 8 [duplicate]
(9 answers)
Closed 6 years ago.
I am trying to create a unique list. I can not use a "Set" because I need to assign some of the values as I iterate though it.
Right now I doing this to create a unique list. Does anyone know a better way?
List<Thing> things = previousThings.stream()
.collect(Collectors.toSet()).stream()
.collect(Collectors.toList());
I was thinking that if I convert it to a set and the back to a list it would eliminate any duplicate entries. I think it needs to be a list so that I can use "List.set(..)" to update according to what might already be in my repository.
for(int i = 0; i < things.size(); i++) {
if(things.get(i).id == null) {
existingThing = thingRepository.getByName(things.get(i).getName());
if(existingThing != null) {
things.set(i, existingThing);
} else {
things.set(i, thingRepository.save(things.get(i));
}
}
}
I thought before that I wouldn't be able to use the .distinct() because it uses .equals() which is based off of 'Thing.id' and some of the 'Things' don't have an 'id' yet. Then I realized that by the end of the forLoop everything is assigned an id by the repository.
List<Thing> things = previousThings;
for(int i = 0; i < things.size(); i++) {
if(things.get(i).id == null) {
existingThing = thingRepository.getByName(things.get(i).getName());
if(existingThing != null) {
things.set(i, existingThing);
} else {
things.set(i, thingRepository.save(things.get(i));
}
}
}
List<Thing> distinctThings = things.stream().distinct().collect(Collectors.toList);
This simple piece of code removes any Statistic in an arrayList if its properties are null. Unfortunately, I'm getting a java.lang.NullPointerException on the first line of the if Statement (if tempStat.serialName==null...). Thoughts?
public static ArrayList<Statistic> removeEmptyStats(ArrayList<Statistic> al) {
Statistic tempStat=new Statistic();
for (int i=0; i<al.size(); i++) {
tempStat=al.get(i);
if (tempStat.serialName==null || tempStat.serialPublisher==null || tempStat.serialISSN==null || tempStat.serialOnlineISSN==null) {
al.remove(i);
}
}
return al;
}
It must be because tempStat itself is null. However you need to be very careful with this.
Say you have 5 elements in your list element 2 is invalid so you remove it, element 3 has now dropped back to element 2, but you're going to move on to check element 3 next, however this is now the old element 4 (if that makes any sense!)
You should not remove entries of a list on which you are doing a loop.
tempstat is null, because when doing for (int i=0; i<al.size(); i++), it stores the initial value of al.size().
Then when you are doing al.get(i) after having removed some values, you can have a i which is higher than the size of the list. (BTW, once you remove a value, it also mean that you will skip one in your list).
You'd to have to use an iterator and iterator.remove().
Iterator<Statistic> iterator = al.iterator();
while(iterator.hasNext()) {
Statistic tempStat = iterator.next();
if (tempStat.serialName==null || tempStat.serialPublisher==null || tempStat.serialISSN==null || tempStat.serialOnlineISSN==null) {
iterator.remove();
}
}
The variable tempStat is null! check the values contained in passed array al
I have a list of strings that represents package directories. I want to iterate the list, to find largest part of the strings where the packages are the same, then extract this substring, subtract that from the original list of strings to get specific packages so I create the appropriate directories.
I was thinking of creating the original list as a static hash set, then using the retainAll method, storing the result in a new String.
Would something like this be the most performant option, or is there a better way to do it?
Many thanks
This works for me, explanation in comments
// returns the length of the longest common prefix of all strings in the given array
public static int longestCommonPrefix(String[] strings) {
// Null or no contents, return 0
if (strings == null || strings.length == 0) {
return 0;
// only 1 element? return it's length
} else if (strings.length == 1 && strings[0] != null) {
return strings[0].length();
// more than 1
} else {
// copy the array and sort it on the lengths of the strings,
// shortest one first.
// this will raise a NullPointerException if an array element is null
String[] copy = Arrays.copyOf(strings, strings.length);
Arrays.sort(copy, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
int result = 0; // init result
// iterate through every letter of the shortest string
for (int i = 0; i < copy[0].length(); i++) {
// compare the corresponding char of all other strings
char currenChar = copy[0].charAt(i);
for (int j = 1; j < strings.length; j++) {
if (currenChar != copy[j].charAt(i)) { // mismatch
return result;
}
}
// all match
result++;
}
// done iterating through shortest string, all matched.
return result;
}
}
If changing the original array does not bother you, you can omit the line String[] copy = Arrays.copyOf(strings, strings.length); and just sort your strings array.
To retrieve the text, change the return type to String and return something like return copy[0].substring(0, result + 1); within the loop and return copy[0]; at the end of the method.
If you are just looking for the single most common package, I would do the following:
Grab the first element from the list (call it the reference package). Using this package name I would iterate through the list. For each remaining element in the list, see if the element contains the reference package. If so move to the next element. If not trim your reference package by one package (taking aa.bb.cc.serverside and converting to aa.bb.cc). Then see if the current element contains this new reference package. Repeat this until the reference package is empty or until the element matches. Then continue down the list of packages.
This will give you the largest most common package. Loop back through removing this from all elements in the list.
EDIT: Slight modification, better keep the . at the end of the package name to ensure complete package name.
Just sort them. The common prefixes will appear first.