So I was trying to get the number of samples but everytime I call this function the available sample list resets due to ArrayList<Sample> available = new ArrayList<Sample>(this.getSample()); So if I call another function that remove or add the sample then call this function it will always be the default plus or minus the size. For example....if this.getSample() size is 5 and there are 2 soils that aren't available. I call the remove function twice but my result will always end with 4 where it should be 3.
public ArrayList<Sample> getAvailableSample() {
ArrayList<Sample> available = new ArrayList<Sample>(this.getSample());
//create a copy of arraylist from sample. (doesn't mess with original data)
for(Sample s : available) { //loop through list
if(s.getSoil()!=null){ //soil is not available
available.remove(s); //remove from list
}
}
//System.out.println("size of available: "+available.size());
return available; //returns number of available samples
}
I could not move the ArrayList<Sample> available = new ArrayList<Sample>(this.getSample()); outside because ArrayList<Sample>(this.getSample()); default is null and I cannot call this class's function without messing up other functions in this or other classes.
Any idea would be appreciated.
You are looping on s, but reading only b.
for(Sample s : available) {
if(s.getSoil()!=null) { // s, not b.
available.remove(s); // s, not b.
}
}
You can read your loop like for each Sample s in available.
Create a Collection c, and then remove it after your loop.
List<Sample> c = new ArrayList<>();
for(Sample s : available) {
if(s.getSoil()!=null) {
c.add(s);
}
}
available.removeAll(c);
Im thinking that the problem is that you cant delete an object that from a list that is being interated.
Can you try doing as below? Instead deleting the Sample that don`t have available soil you can create a new list with only the objects that have soil.
public ArrayList<Sample> getAvailableSample() {
ArrayList<Sample> available = new ArrayList<Sample>();
for(Sample s : this.getSample()) { //loop through list
if(s.getSoil()==null){ //soil is available
available.add(s); //add into the available list
}
}
//System.out.println("size of available: "+available.size());
return available; //returns number of available samples
}
Related
I'm facing a weird behavior in my Java code using List.
The code is very simple, I have a List of Object called AccessRequest which comes from a database and I'm using this first List to create a new one but with a filter to select only a few objects.
Here is the code :
private void updateCommentIfNeeded() {
List<AccessRequest> accessRequestList = getAllRequest();
List<AccessRequest> commentsList = getCommentsListProcessedManually(accessRequestList);
}
public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> accessRequests) {
accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));
if (accessRequests.size() != 0) {
SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
}
return accessRequests;
}
I'm supposed to get a second List only containing the objects that has their comments to To be processed manually, which I do. But the weird part is that the first List also takes the value of the second as if I wrote accessRequestList = commentsList but there is no such thing and I'm using local variable.
Ex :
I have 3 objects in my first List, but only one containing the required comment
Both list ends with containing the only objects containing the comment
I'm kind of lost here if anyone has an idea !
Your method getCommentsListProcessedManually modifies the list you're passing. I believe you're operating under the assumption that passing the list as a parameter somehow creates a copy of the list, whereas what is actually happening is that a reference to the list is passed by value.
There are several ways to solve this, but the easiest is to simply create a copy of your input list at the start of your method:
public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> input) {
List<AccessRequest> accessRequests = new ArrayList<>(input);
accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));
if (accessRequests.size() != 0) {
SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
}
return accessRequests;
}
You could also use the Stream API for this (using the filter operation), but that's quite a bit trickier in this situation.
You are passing a reference of the list to the method getCommentsListProcessedManually.
So accessRequestList and the one passed as a parameter are the same, hence any operation done to the list is done to the same list.
You can create a copy of the list before passing it as a parameter:
List<AccessRequest> newList = new ArrayList<AccessRequest>(accessRequestList);
I'm trying to do a swing application which adds names to an ArrayList and then displays it in Jcombobox.I already did the window and everything but I can't seem to get the hang off detecting duplicate names.
I tried
btnnext.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent e) {
if(checkDuplicate(names)==true)
{
names.add(txtname.getText());
txtname.setText("");
}
else {
JOptionPane.showMessageDialog(null,"DUPLICATE! do not add");
}
}
});
public static boolean checkDuplicate(ArrayList<String> list) {
HashSet set = new HashSet();
for (int i = 0; i < list.size(); i++) {
boolean val = set.add(list.get(i));
if (val == false) {
return val;
}
}
return true;
}
It only says that I have duplicate when I already add it to the ArrayList and when I get the message I can't add anything else.
input example:
test
test
and then it stops accepting new Strings and only displays the message DUPLICATE! do not add
As I said in my comment:
This happens because you are basically creating a Set view of your ArrayList every time you call checkDuplicate rather than comparing the item you're trying to add with the existing list. In other words your checkDuplicate is written such that it only returns true when a duplicate already exists within the list. You need to compare the new item with the list instead. Step through your logic carefully either with a debugger or by manually writing down the values of your variables and you will see the problem.
You could simply change this line:
if(checkDuplicate(names)==true)
to this:
if(!names.contains(txtname.getText()))
You don't really need checkDuplicate since it's "reinventing the wheel" so to speak. ArrayList already provides a contains method that you can use to your advantage.
public boolean isConnectedTo(Suspect aSuspect){
boolean flag = false;
Registry tempRegistry = new Registry();
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
System.out.println("here");
for(String PhoneNums : phoneNumbers){
if(PhoneNums.equals(comms.GetTransmitter())) {
for(String numbers : aSuspect.getNumbersList()) {
if(numbers.equals(comms.GetReceiver()))
flag = true;
}
}
}
}
return flag;
}
So I am trying to create a program that among other things, it will search two ArrayLists(TempComs and phoneNumbers) and it will return true or false whether a string in the first is the same with a string in the second or not. I create the new ArrayList TempComms with the method tempRegistry.GetComms(). GetComms() is a method in another class, (class Registry) and has just a return communications; command, communications is an ArrayList in the class Registry.(The ArrayList phoneNumbers is an arrayList of the class the code is into.) So normally with with
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
the ArrayList TempComms must be the same with ArrayList communication that exists in the other class. But I figured out that for some reason the problem is in TempComms, because the first for is never running(For that reason I used System.out.println("here"); but it never printed). I searched and tried a lot to find the solution of this problem of my own, but I didn't manage to make some progress, so I would be grateful if someone who knows where's the problem or what I do wrong tell me about it. Thanks anyway.
You are creating a new instance of the Registry which contains a list (comms).
Registry tempRegistry = new Registry();
Then you are trying to get that comm list by calling tempRegistry.GetComms() .
Unless you are populating this communication list in the constructor Registry() (not only instantiating, you should add some entries as well),
that list will be empty when for loop is called.
(Because you are clearly NOT populating it after creating the instance tempRegistry and before calling the for loop.
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
Therefore, the TempComms list is also an empty list. Which is why the inside code of the for loop is not executing.
I'm getting a very strange action in my code. I have an ArrayList of the following class.
class mySocket
{
public String name;
public Socket sck;
public mySocket(String n,Socket s)
{
this.name=n;
this.sck=s;
}
}
I declare the object like this
ArrayList<mySocket> handler = new ArrayList<>();
Now the problem is that when I try to remove an item using this method:
public void removeByName(String name)
{
synchronized(this)
{
mySocket t;
int i;
for(i=0;i<handler.size();i++)
{
t=handler.get(i);
if((t.name.equals(name)))
{
handler.remove(i);
break;
}
}
}
}
The remove function clears everything that follows the index.
For Example:
if this ArrayList has 3 elements and I call handler.remove(1) it removes not only 1 but also the object on line 2.
I think your issue is that you are using an indexed for loop and removing by index. In your example, if your list has 3 elements and you remove index 1, the object that was at index 2 is still there. It's just now at index 1.
A better way to do what you're attempting is to use an iterator or for-each loop.
//code outside for loop the same
for( mySocket socket : handler ) {
if((socket.name.equals(name)))
{
handler.remove(socket);
break;
}
}
Is the ordering of your mySocket objects important? If not, storing them in a Map keyed by name would save you some trouble. Then you would just call handler.remove(name). This operation is safe, even if name doesn't exist in the map. Also, for current uses of the collection handler that don't care aobut the name, you can retrieve the unordered Set of mySockets by calling map.values(). You would then be able to iterate over that Set using an iterator or for-each as above.
You CAN NOT remove items in a Collection while looping through them, the result, as you have seen, is undefined.
You either have to build a list of items to be removed and use
originalList.removeAll(itemsToBeRemoved);
Or you build your loop using an iterator.
Iterator<mySocket> handlerIterator = handler.iterator();
while (handlerIterator.hasNext()) {
mySocket t = handlerIterator.next();
if (t.name.equals(name)) {
handlerIterator.remove();
}
}
I encountered this issue while working with the Java Collections API. Basically this is a support method for an implementation of Kruskal's algorithm for finding an MST. I created this class for implementing the union/find algorithm.
My question, as I was able to find a work around, is that does anybody know of any reason why the remove method in the "union" method would not work consistently. That is at run time it would remove some elements and not others. For example I implemented this for a task involving cities and it seemed to not like removing some cities. In particular it repeatedly stumbled on a couple of different sets, but always the same ones. I wondered whether it was a object reference issue, i.e. whether I was testing the wrong thing, but I could not get around it.
I know the rest of my work was correct as I was able to replace it with a loop that eliminated the element, and the algorithm executed perfectly. Probably with slightly worse performance, however.
I was wondering whether anybody can see a mistake. Also I should note that I called it from different class, however, the calls were made with elements that were retrieved using the find method. Note that the find method must work well, since simply altering the remove method made the whole thing work, i.e. it was finding and returning the appropriate objects.
Thanks
Oscar
/*
* A constructor for creating a new object of this class.
*/
DisjointSets()
{
underlying = new HashSet<HashSet<String>>();
}
/*
* A method for adding a set to this DisjointSets object
*/
void add(HashSet<String> h)
{
underlying.add(h);
}
/*
* A method for finding an element in this DisjointSet object.
*/
HashSet<String> find(String s)
{
// Check each set in the DisjointSets object
for(HashSet<String> h: underlying)
{
if(h.contains(s))
{
return h;
}
}
return null;
}
/*
* A method for combining to subsets of the DisjointSets
*/
void union(HashSet<String> h1, HashSet<String> h2)
{
System.out.print("CHECK ON DS\n");
System.out.print("*********************\n");
System.out.print("H1 is : { ");
for (HashSet<String> n: underlying)
{
System.out.print("Set is : { ");
for (String h : n)
{
System.out.print(h + " , ");
}
System.out.print("} \n ");
}
// Add the objects of h1 to h2
// DOES NOT WORK CONSISTENTLY
h1.addAll(h2);
underlying.remove(h2);
}
}
And I replaced it with
HashSet<HashSet<String>> temp = new HashSet<HashSet<String>>();
for(HashSet<String> f: underlying)
{
if(f != h2)
{
temp.add(f);
}
}
underlying = temp;
The problem is that when you modify the contents of one of the nested HashSets, you screw up the internals of the outer HashSet (because the hashCode() of the nested HashSet has changed). in order to maintain this collection correctly, whenever you want to modify one of the nested HashSets you must first remove it from the outer HashSet and then re-add it (if necessary).
(you don't really provide enough code to figure out if that's truly the problem, but that's my best guess).
Set<Set<String>> outerSet = new HashSet<String>();
Set<String> innerSet = new HashSet<String>();
innerSet.add("foo");
outerSet.add(innerSet);
// *** BROKEN ***
innerSet.add("bar"); // <- adding element to innerSet changes result of innerSet.hashCode()
outerSet.remove(innerSet); // <- this may or may not work because outerSet is _broken_
// *** BROKEN ***
// *** CORRECT ***
outerSet.remove(innerSet);
innerSet.add("bar");
// now you can put innerSet back in outerSet if necessary
Following up on #jtahlborn's answer, the contract for AbstractSet.hashCode() says
Returns the hash code value for this
set. The hash code of a set is defined
to be the sum of the hash codes of the
elements in the set. This ensures that
s1.equals(s2) implies that
s1.hashCode()==s2.hashCode() for any
two sets s1 and s2, as required by the
general contract of Object.hashCode.
This implementation enumerates over
the set, calling the hashCode method
on each element in the collection, and
adding up the results.
Code to demonstrate #jtahlborn's answer (which is correct)
import java.util.HashSet;
import java.util.Set;
public class TestHashSetHashCode {
public static void main(String[] args)
{
Set<String> strings = new HashSet<String>();
strings.add("one");
strings.add("two");
strings.add("three");
strings.add("four");
strings.add("five");
Set<String> test = new HashSet<String>();
System.out.println("Code "+test.hashCode());
for (String s : strings) {
test.add(s);
System.out.println("Code "+test.hashCode());
}
}
}
Outputs
Code 0
Code 115276
Code 3258622
Code 3368804
Code 113708290
Code 116857384
One more reason to add to the list to make use of immutable collections wherever possible.