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^^)
Related
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.
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.
I want to know the best way to compare a string to a list of strings. Here is the code I have in my mind, but it's clear that it's not good in terms of time complexity.
for (String large : list1) {
for (String small : list2) {
if (large.contains(small)) {
// DO SOMETHING
} else {
// NOT FOR ME
}
}
// FURTHER MANIPULATION OF STRING
}
Both lists of strings can contain more than thousand values, so the worst case complexity can rise to 1000×1000×length which is a mess. I want to know the best way to perform the task of comparing a string with a list of strings, in the given scenario above.
You could just do this:
for (String small : list2) {
if (set1.contains(small)) {
// DO SOMETHING
} else {
// NOT FOR ME
}
}
set1 should be the larger list of String, and instead of keeping it as a List<String>, use a Set<String> or a HashSet<String>
Thanks to the first answer by sandeep. Here is the solution:
List<String> firstCollection = new ArrayList<>();
Set<String> secondCollection = new HashSet<>();
//POPULATE BOTH LISTS HERE.
for(String string: firstCollection){
if(secondCollection.contains(string)){
//YES, THE STRING IS THERE IN THE SECOND LIST
}else{
//NOPE, THE STRING IS NOT THERE IN THE SECOND LIST
}
}
This is, unfortunately, a difficult and messy problem. It's because you're checking whether a small string is a substring of a bunch of large strings, instead of checking that the small string is equal to a bunch of large strings.
The best solution depends on exactly what problem you need to solve, but here is a reasonable first attempt:
In a temporary place, concatenate all the large strings together, then construct a suffix tree on this long concatenated string. With this structure, we should be able to find all the substring matches of any given small among all the large quickly.
This is most certainly a noob question, but I haven't been able to find a good answer on Google or here, so I have to ask:
What kinda list should I use in Java, when I just want a value to be added once?
The problem is that I'm doing a web technology project in college (a webshop), and I have this cloud I connect too. I can the request the customer ID´s from those who bought items in my shop. What I want to do is extract these ID´s and add them to a list. But when extracting them I get the ID returned for every item they have bought, so I want a list that can check: "This value is already in this list, do nothing", or "This ID is not in the list, lets add the ID"
Is there a list that can do this, or a way to do it with a list without it getting too complicated?
You want a Set, this is the data structure that prevents duplicates. This is a Collection so you can define a function like so:
public Collection<MyObject> foo()
{
return new HashSet<MyObject>();
}
and at a later time change the return internally to this:
public Collection<MyObject> foo()
{
return new ArrayList<MyObject>();
}
And your API won't break.
A Set contains every value only once.
Though, the problem with HashSet is that the order in which the elements were added gets lost. So if you want to preserve the order of elements, I would suggest using a LinkedHashSet.
With a LinkedHashSet, iterating over the elements will return them in the order they were inserted.
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
hashSet.add("first");
hashSet.add("second");
hashSet.add("third");
for (String s : hashSet) {
System.out.println(s); // no particular order
}
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("first");
linkedHashSet.add("second");
linkedHashSet.add("third");
for (String s : linkedHashSet) {
System.out.println(s); // "first", "second", "third"
}
}
public boolean insertRecord(Programmer targetProgrammer, List programmerList) {
boolean flag = false;
for (Programmer p : programmerList){
if (targetProgrammer.getId() == p.getId()) {
return true;
}
}
return flag;
}
// Then when you invoke:
Programmer target = new Programmer(1,"Dev","Java");
if (!insertRecord(target, myList)) {
myList.add(target);
}
What you will be looking for is a Set, as a Set is a Collection that contains no duplicates.
There are a few types that you could use depending on your needs:
HashSet
LinkedHashSet
CopyOnWriteArraySet
EnumSet
TreeSet
ConcurrentSkipListSet
Better use HashSet as it takes care of your problem of unique IDs implicitly. Still better is SortedSet where you can have the unique elements printed in sorted order automatically.
I have Two Arraylist RunningProcessList AllProcessList its contains following values are
RunningProcessList:
Receiver.jar
AllProcessList:
Receiver.jar
Sender.jar
Timeout.jar
TimeourServer.jar
AllProcessList arraylist contains the all java processes , RunningProcessList arraylist contains currently running process. I want to compare these two arraylist and I want to display If the process is not running. For Example compare two list and want to display following process is not running.
Result:
Sender.jar
Timeout.jar
TimeourServer.jar
I used the following code but its not working.
Object Result = null;
for (int i = 0; i <AllProcessList.size(); i++) {
for (int j = 0; j < RunningProcessList.size(); j++) {
if( AllProcessList.get(i) != ( RunningProcessList.get(j))) {
System.out.println( RunningProcessList.get(j)));
Result =RunningProcessList.get(j);
}
if(AllProcessList.get(i) != ( RunningProcessList.get(j))) {
list3.add(Result);
}
}
}
Take a look at the documentation for List, ecpecially the removeAll() method.
List result = new ArrayList(AllProcessList);
result.removeAll(RunningProcessList);
You could then iterate over that list and call System.out.println if you wanted, as you've done above... but is that what you want to do?
Assuming your lists are not too long, you can just collect all elements of AllProcessList that are not in the RunningProceesList
for (Object process : AllProcessList) {
if (!RunningProcessList.contains(process)) {
list3.add(process);
}
}
it's important that the RunningProcessList contains the same instances as the AllProcessList (or the objects must implement a functional equals method).
it would be better if your list contains instances of Process (or some other dedicated class).
List<Process> AllProcessList = new ArrayList<Process>();
List<Process> RunningProcessList = new ArrayList<Process>();
List<Process> list3 = new ArrayList<Process>();
...
for (Process process : AllProcessList) {
if (!RunningProcessList.contains(process)) {
list3.add(process);
}
}
English is not my first (neither second) language, any correction is welcome
Hi lakshmi,
I upvoted noelmarkham's answer as I think it's the best code wise and suits Your needs. So I'm not going to add another code snippet to this already long list, I just wanted to point You towards two things:
If Your processes are unique (their name/id whatever), You might consider to use (Hash)Sets in order to store them for better performance of Your desired operations. This should only be a concern when Your lists are large.
What about using ActiveProcesses and InactiveProccesses instead of Your current two lists? If a process changes its state You just have to remove it from one list and insert it into the other. This would lead to an overall cleaner design and You could access the not-running processes immediately.
Greetings
Depending on the type on AllProcessList and RunningProcessList (whocu should be allProcessList and runningProcessList to follow the Java naming conventions) the following will not work:
if ( AllProcessList.get(i) != ( RunningProcessList.get(j))) {
you should replace it with
if (!(AllProcessList.get(i).equals(RunningProcessList.get(j)))) {
!= compares physical equality, are the two things the exact same "new"ed object?
.equals(Object) compared locaical equality, ate the two things the "same"?
To do that you will need to override the equals and hashCode methods. Here is an article on that.
If the class is a built in Java library one then odds are equals and hashCode are done.
For sorted lists, the following is O(n). If a sort is needed, this method becomes O(nlogn).
public void compareLists(final List<T> allProcesses, final List<T> runningProcesses) {
// Assume lists are sorted, if not call Collection.sort() on each list (making this O(nlogn))
final Iterator<T> allIter = allProcesses.iterator();
final Iterator<T> runningIter = runningProcesses.iterator();
T allEntry;
T runningEntry;
while (allIter.hasNext() && runningIter.hasNext()) {
allEntry = allIter.next();
runningEntry = runningIter.next();
while (!allEntry.equals(runningEntry) && allIter.hasNext()) {
System.out.println(allEntry);
allEntry = allIter.next();
}
// Now we know allEntry == runningEntry, so we can go through to the next iteration
}
// No more running processes, so just print the remaining entries in the all processes list
while (allIter.hasNext()) {
System.out.println(allIter.next());
}
}