I am building an app in Android Studio with various tree and shrub preferences and checkboxes. You check a box that indicates you want a tree with a certain trait, and the code runs through an arraylist of all the trees and shrubs in the inventory (I created a Plant class, with attributes like size, name, fruit, etc) and adds all String names of objects that match that criteria to another arraylist of strings to be printed (called 'selections') on a different screen (duplicates are eliminated before printing in another step).
The problem is with removing objects from an arraylist during iteration. Here is a sample:
if (cb_s.isChecked()) {
for(Plant p : test){
if(p.getSize() == "s"){
selection.add(p.getName());
}
else{
selection.remove(p.getName());
test.remove(p);
}
}
}
if (cb_m.isChecked()) {
for(Plant p : test){
if(p.getSize() == "m"){
selection.add(p.getName());
}
else{
selection.remove(p.getName());
test.remove(p);
}
}
}
if (cb_l.isChecked()) {
for(Plant p : test){
if(p.getSize() == "l"){
selection.add(p.getName());
}
else{
selection.remove(p.getName());
test.remove(p);
}
}
}
For every checkbox checked, it runs through an arraylist named 'test' to pick out the plants that correspond to the checkbox (in this case, these three blocks would pick out small, medium, and large plants - s, m, and l) and adds them to another arraylist of strings to be printed later on. It also removes plants from the first arraylist, test, so that they cant be compared if other checkboxes are checked (this would result in a final list of plants that dont meet all criteria selected with checkboxes).
Java doesnt like the way I am trying to remove elements from the arraylist 'test', since that is what I am iterating through. What would be the proper way to remove objects during iteration if they dont meet the criteria? Ive heard that I should use the iterator of the actual collection? How would I go about doing that for this code?
Thanks!
Don't compare String with == method, but do it with .equals in all cases, for example
p.getSize().equals("s")
instead
p.getSize() == "s"
If you want to remove items from a list while iterating over the list you should use the iterator for this:
Iterator<Plant> iterator = test.iterator();
while (iterator.hasNext()) {
p = iterator.next();
if(p.getSize().equals("l")){
selection.add(p.getName());
} else {
selection.remove(p.getName());
iterator.remove();
}
}
Also you should compare String with the equals method. == will check if the objects are the same instance while equals checks for the same content in the Strings.
Related
Any idea why contains not working here, these statement always evaluating false firstSchema.contains(firstSchema.get(0))
List<String> firstSchema = new ArrayList<String>();
firstSchema.add(0,"test");
firstSchema.add(1,"testy");
if(!(firstSchema.contains(firstSchema))){
System.out.println("hey arraylist content matched");
}
I need to get true if any one or more or all elements from one arraylist matched with other arraylist elements
The simplest way to check if a list contains any elements from another list is to call contains() on one of the lists, passing each element as an argument in turn. Something like:
public <E> boolean slowListContains(List<E> a, List<E> b) {
for (E element : a) {
if (b.contains(element)) {
return true;
}
}
return false;
}
This is slow, however, because contains() is a linear operation (O(n)), and since we're calling it in a loop the slowListContains() function takes quadratic time (O(n^2)) which is poor. We can do better.
A Set (or more precisely a hash-based set such as HashSet) has an efficient contains() method which runs in less-than-linear time (constant time in the case of HashSet). Converting one or the other list into a Set will make the loop in slowListContains() much faster. Something like:
public <E> boolean fasterListContains(List<E> a, List<E> b) {
Set<E> aSet = new HashSet<>();
aSet.addAll(a);
for (E element : b) {
if (aSet.contains(b)) {
return true;
}
}
return false;
}
This isn't perfect, but it's certainly much faster than the naive solution. A slight improvement would be to always convert the smaller list into the Set, rather than the first one. You could also take arbitrary Iterable parameters rather than List parameters, then check if either of them are already a Set and if so skip the set-construction step.
Your if(!(firstSchema.contains(firstSchema))) loop is wrong. You are trying to find a match in list with itself. You can not check if a list contains itself.
From java doc below is how contains works
Returns <tt>true</tt> if this list contains the specified element.
More formally, returns <tt>true</tt> if and only if this list contains
at least one element <tt>e</tt> such that
<tt>(o==null ? e==null : o.equals(e))</tt>.
You are checking it incorrectly. See firstSchema.contains(firstSchema) is wrong arrayList.contains(arrayList) won't work.
Secondly (firstSchema.contains("test")) returns true as array list does contains test and ! negating the result will not pass if statement because !true = false.
if(firstSchema.contains("test")) {
System.out.println("Match found !");
}
if(!firstSchema.contains("test")) {
System.out.println("Match not found !");
}
If want to check if one list has matching elements , you can do something like this.
List<String> firstSchema = new ArrayList<String>();
firstSchema.add(0,"test");
firstSchema.add(1,"testy");
List<String> testList = new ArrayList<String>(firstSchema);
testList.removeAll(firstSchema);
if(testList.size()<firstSchema.size()){
System.out.println("some elements match");
}
You can also use retainAll similarly
The simplest way is to use Java 8 streams.
if(firstList.stream().anyMatch(secondList::contains))
System.out.println("Content matched");
For improved efficiency (if you're working with enough data for it to actually matter) and if possible (unique values), the secondList can be turned into a HashSet.
suppose i want to write a method to remove a particular occurrence in a list.
if the key is not on the list, return the list as it is.
methods that are given and i can use :
boolean isEmpty- true if and only if the list is empty
addFirst - adds a given object to the front of the list
removeFirst - removes an object from the front of the list
boolean isMem - checks if the given object is a member in the list
reverse - reverse the order of the items in the list
one of the codes i have found regarding the question is this code:
public void removeAllOccurrences(Object key){
List ans = new List();
while (!isEmpty()){
Object data = removeFirst();
if (!data.equals(key)){
ans.addFirst(data);
}
}
while(!ans.isEmpty()){
addFirst(ans.removeFirst());
but i didn't get the last part : while the list is not empty, add an item in front of the list, and then remove it.. ?
also, i would suggest the following code, will gladly hear your professional opinion:
List ans = new list();
if (!(isMember(key) )
return new list();
else
while (!ans.isEmpty ) {
Link first = curr.link;
if (!(data.equals(key))
ans.addFirst(data) ;
curr=curr.next;
}
As for the first question: the while block has emptied this list, and the ans object contains the new list, so, at the end, the method drains the ans contents to this list.
Regarding the second code block, the while block will never execute because the ans object has just been created, so ans.isEmpty() will always return true.
The title sheds good light on the trouble I am having, here is my code:
// fields required for traversal
private Queue<ArrayList<String>> q;
private ArrayList<ArrayList<String>> r;
Set<String> stringList = getMeStrings();
for(String s : stringList)
{
ArrayList<String> stringsRoute = new ArrayList<String>();
stringsRoute.add(getSomeString());
stringsRoute.add(s);
if(!r.contains(stringList))
{
if(!q.contains(stringList))
{
q.add(stringList);
}
r.add(stringList);
}
}
My If statement inside the For loop always fails, and I think the reason is because I am creating a new ArrayList object (different reference) and my If statement isn't checking to see if the contents of each of the ArrayLists in [ r ] contain the same elements in same order .. etc
I know one needs to use .equals in order to find out if two ArrayLists are similiar, but I have an ArrayList that houses many other ArrayLists.
How can I check if the parent ArrayList contains an ArrayList that equates to the new ArrayList I am creating?
I hope it is clear what I am trying to achieve.
Thanks
you need to traverse the whole ArrayList and then compare each element of the ArrayList with StringsRoute using equals method of ArrayList class.
To implement the foreach loop you could consider getting the size of ArrayList. If we have ArrayList ar=new ArrayList(); we can user ar.size() to return the size and then simply run a for loop ar.size() times to iterate each element in the corressponding ArrayList.
Hopefully that solves your problem.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html#equals%28java.lang.Object%29
For "StringsRoute" to be contained in "r" , there must be a list in "r" with the same elements in the same order.
Arrays.asList("1","2") .equals(Arrays.asList("2","1")) == false
Arrays.asList("1","2") .equals(Arrays.asList("1","2")) == true
Arrays.asList(Arrays.asList("1","2")).contains(Arrays.asList("1","2")) == true
Arrays.asList(Arrays.asList("1","2")).contains(Arrays.asList("2","1")) == false
May be you want to use a list of sets to avoid struggling with order.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/AbstractSet.html#equals%28java.lang.Object%29
List< Set< String > > r;
Since:
new HashSet(Arrays.asList("1","2")).equals(new HashSet(Arrays.asList("2","1"))) == true
I have three List<String> variables: classFiles, usernames, and fileDirectories. I have a String (a list of strings but I will be comparing every string in the list with the loop below) that consists of one item from each of the lists. I want to loop through all three lists and check if one value from all three of the lists are in the String
What would be the best way to go about this?
for(String classFile:classFiles) {
//if contains classfile statement
for(String username:usernames) {
//if contains username statement
for(String fileDirectory:fileDirectories) {
//if contains filedirectory statement
}
}
}
or
for(String classFile:classFiles) {
for(String username:usernames) {
for(String fileDirectory:fileDirectories) {
//if statement
}
}
}
or
for(String classFile:classFiles) {
//make list of files that contain classFile
}
for(String username:usernames) {
//remove items from list that do not contain username
}
for(String fileDirectory:fileDirectories){
//remove items from list that do not contain fileDirectory
}
Or is there a better way to do this?
EDIT: Example
classFiles - a1, a2, a3
usernames - noc1, noc2, noc3
fileDirectories - C:/projects/a1/noc1/example.java, C:/projects/a1/ad3/example.java
and the string to check
String - C:/bin/a1/noc1/example.class
what i want to do is if both the fileDirectory and String contain a classFile and username, then add it to a list
so in this example C:/bin/a1/noc1/example.class will be added to the list but C:/bin/a4/fd1/example.class wont be or C:/bin/a3/noc3/example.class would not be added
When you perform remove operations for-each loop is not best choice. You should use Iterator and remove on iterator to avoid concurrent modification exception.
Instead
for(String fileDirectory:fileDirectories){
//remove items from list that do not contain fileDirectory
}
You should do something like
Iterator iter = fileDirectores.iterator();
while(iter.hasNext())
{
//Get next
//Do your check
iter.remove();
}
This leads to having three separate iterates to full fill your requirement.
It is sometimes best to define the function you're actually trying to write:
/**
* Checks to see if candidate has one string in each of classFiles, usernames and fileDirectories
*/
public boolean hasEssentialComponents(List<String> candidate) {
//Code here
}
Now, your first option has a very long maximum run time O(n^3). If you expect the function to generally fail what it means is that for each item in your three lists you are looping through the next list. Most of this is redundant, and you will have a huge performance impact if these lists are long.
The second one is subtly different, but with the same total runtime.
The third is clearly better; in this you can fail as soon as you find out that a list doesn't have a component and you never check a list for a component twice. However, Java provides some sugar that can make this easier.
public boolean hasEssentialComponents(List<String> candidates) {
//Sanity check the data
if (candidate.size() != 3) { return false; } //I'm assuming a 'good' candidate has only three items.
valid = true;
for (String candidate:candidates) {
if (valid &&
! ( check(this.classFiles, candidate)
|| check(this.usernames, candidate)
|| check(this.fileDirectories, candidate) )
)) {
valid = false;
}
}
return valid;
}
private boolean check(List<String> masterList, String candidate) {
return masterList.contains(candidate);
}
Now, I'm being unnecessarily verbose here to make sure to tease out the parts of the problem. Please note that you should use Java built in functions when possible; they're well optimized. Do not add your lists together; you're spending unnecessary time copying. Also, make each comparison only once if that is all you need: note that if you know where element in your string list should be in one of your master lists, this can be made even better.
Finally, I really recommend you write out a method signature first. It forces you to think about what you're actually trying to do.
So I take it you want to get the intersection between all three lists?
Just use the retainAll method on List.
classFiles.retainAll(usernames);
classFiles.retainAll(fileDirectories);
Now classFiles will just have the intersection between all three lists.
Can you consider to use a HashSet or HashMap to access quickly your string value (with .contains(string))?
It will eliminates the loops.
I would do this way if I understand well the problem (not sure^^)
I have a java.util.ArrayList<Item> and an Item object.
Now, I want to obtain the number of times the Item is stored in the arraylist.
I know that I can do arrayList.contains() check but it returns true, irrespective of whether it contains one or more Items.
Q1. How can I find the number of time the Item is stored in the list?
Q2. Also, If the list contains more than one Item, then how can I determine the index of other Items because arrayList.indexOf(item) returns the index of only first Item every time?
You can use Collections class:
public static int frequency(Collection<?> c, Object o)
Returns the number of elements in the specified collection equal to the specified object. More formally, returns the number of elements e in the collection such that (o == null ? e == null : o.equals(e)).
If you need to count occurencies of a long list many times I suggest you to use an HashMap to store the counters and update them while you insert new items to the list. This would avoid calculating any kind of counters.. but of course you won't have indices.
HashMap<Item, Integer> counters = new HashMap<Item, Integer>(5000);
ArrayList<Item> items = new ArrayList<Item>(5000);
void insert(Item newEl)
{
if (counters.contains(newEl))
counters.put(newEl, counters.get(newEl)+1);
else
counters.put(newEl, 1);
items.add(newEl);
}
A final hint: you can use other collections framework (like Apache Collections) and use a Bag datastructure that is described as
Defines a collection that counts the number of times an object appears in the collection.
So exactly what you need..
This is easy to do by hand.
public int countNumberEqual(ArrayList<Item> itemList, Item itemToCheck) {
int count = 0;
for (Item i : itemList) {
if (i.equals(itemToCheck)) {
count++;
}
}
return count;
}
Keep in mind that if you don't override equals in your Item class, this method will use object identity (as this is the implementation of Object.equals()).
Edit: Regarding your second question (please try to limit posts to one question apiece), you can do this by hand as well.
public List<Integer> indices(ArrayList<Item> items, Item itemToCheck) {
ArrayList<Integer> ret = new ArrayList<Integer>();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).equals(itemToCheck)) {
ret.add(i);
}
}
return ret;
}
As the other respondents have already said, if you're firmly committed to storing your items in an unordered ArrayList, then counting items will take O(n) time, where n is the number of items in the list. Here at SO, we give advice but we don't do magic!
As I just hinted, if the list gets searched a lot more than it's modified, it might make sense to keep it sorted. If your list is sorted then you can find your item in O(log n) time, which is a lot quicker; and if you have a hashcode implementation that goes well with your equals, all the identical items will be right next to each other.
Another possibility would be to create and maintain two data structures in parallel. You could use a HashMap containing your items as keys and their count as values. You'd be obligated to update this second structure any time your list changes, but item count lookups would be o(1).
I could be wrong, but it seems to me like the data structure you actually want might be a Multiset (from google-collections/guava) rather than a List. It allows multiples, unlike Set, but doesn't actually care about the order. Given that, it has a int count(Object element) method that does exactly what you want. And since it isn't a list and has implementations backed by a HashMap, getting the count is considerably more efficient.
Thanks for your all nice suggestion. But this below code is really very useful as we dont have any search method with List that can give number of occurance.
void insert(Item newEl)
{
if (counters.contains(newEl))
counters.put(newEl, counters.get(newEl)+1);
else
counters.put(newEl, 1);
items.add(newEl);
}
Thanks to Jack. Good posting.
Thanks,
Binod Suman
http://binodsuman.blogspot.com
I know this is an old post, but since I did not see a hash map solution, I decided to add a pseudo code on hash-map for anyone that needs it in the future. Assuming arraylist and Float data types.
Map<Float,Float> hm = new HashMap<>();
for(float k : Arralistentry) {
Float j = hm.get(k);
hm.put(k,(j==null ? 1 : j+1));
}
for(Map.Entry<Float, Float> value : hm.entrySet()) {
System.out.println("\n" +value.getKey()+" occurs : "+value.getValue()+" times");
}