Arraylist toString() method and duplicate values - java

Below I have posted a snippet of code I have written whilst trying to replicate the game minesweeper in very simplistic terms. I've got a slight query...
The code below generates a pair of co-ordinates, checks to see if the particular co-ordinates are already held in the ArrayList, and if not, adds them to the list, repeating this process until I have a list of ten mine locations. on running the program I have found that the list contains duplicates when it shouldn't...
public class MineSweeper {
private static ArrayList mines;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
MineSweeper ms = new MineSweeper();
}
public MineSweeper(){
mines = new ArrayList(10);
generateMines();
showMines();
}
private void generateMines(){
int x = 0, y = 0, mineCount = 0;
Random rnd = new Random();
StringBuilder str = new StringBuilder();
while(mineCount != 10)
{
x = rnd.nextInt(9) + 1;
y = rnd.nextInt(9) + 1;
str.append(x).append(",").append(y);
if(!(mines.contains(str.toString())))
{
mines.add(str);
mineCount ++;
}
str = new StringBuilder();
}
}
private void showMines(){
System.out.println(mines.toString());
}
}
I believed that my if statement would catch any duplicates but was wrong.
I eventually solved the problem by changing the if statement to if(!(mines.toString().contains(str)))
Can somebody enlighten me on the difference please?

You are checking if mines contains str.toString(), but adding str, which is a StringBuilder instance. Since all the objects you're adding are StringBuilders, mines can't contain a String.
You should choose which class you're going with, and stick to it. E.g., with Strings:
if (!(mines.contains(str.toString()))) {
mines.add(str.toString());
mineCount++;
}

It could be an issue with the "if(!(mines.contains(str.toString())))", i just dont know how the coordinates are saved and accessed by the "ArrayList" object.

ArrayList contains StringBuilder's and in mines.contains(str.toString()) you compare to a String (str.toString) so you compare a StringBuilder with a String thus they are never equal.
You have quite a number of other problems as well, for example mines field is static, Random is not, etc

if we look at your if statement:
mines.contains(str.toString())
mines is an ArrayList of generic type StringBuilder (because it had undefined generic type it automatically uses ArrayList<Object> ). This can be checked if you do this
System.out.println(mines.get(1) instanceof StringBuilder); //print true
str is a StringBuilder object which you have cast to a String. You are thus comparing a StringBuilder object to a String object. It is important to note that contains() uses equals() for comparison.
this can be illustrated with this example:
StringBuilder testStrB = new StringBuilder("test");
System.out.println(testStrB.equals(testStrB.toString())); //print false
in fact, I get the warning that equals() is used on incompatible types.
with your working statement
mines.toString().contains(str)
it seems that contains() accepts a CharSequence, which is a super-interface of StringBuilder. As mines.toString uses contains() of the entire String searching for a CharSequence represented by StringBuilder, it works.
in summary:
your initial (non-working) if statement tried to use (for each element of mines)
StringBuilder.equals(String)
whereas your working if statement used
String.contains(StringBuilder)
which allows StringBuilder to be used as a CharSequence and thus compared.
for interest:
System.out.println(testStrB.toString().equals(testStrB)); //prints false
// (and incompatible types warning)
so a String cannot EQUAL a StringBuilder, but can CONTAIN it. Probably because equals() takes an Object and contains() takes a CharSequence

Related

How can I change the the string contents in String array using enhanced-for loops?

I'm a beginner in Java I have some questions regarding the enhanced for loop and string arrays.
In the source code below, I've been trying to change the contents of the arrays using the enhanced-for loops.
It seems that I can't change the contents in the the String array(arrString), but I don't know exactly why. (It works fine for StringBuilder objects.)
I am a bit confused because I could actually do operations like str1+=str2 and change the String contents (although this operation is done via StringBuilder class) in normal situations.
Can anyone point out why this is happening and if there's any misunderstanding on my part?
class EnhancedForTest{
public static void main(String[] args){
//StringBuilder
StringBuilder[] arrStringBuilder=new StringBuilder[]{new StringBuilder("Hello1"), new
StringBuilder("Hello2"),new StringBuilder("Hello3")};
for(StringBuilder e: arrStringBuilder){
e.append("!");
}
for(StringBuilder e:arrStringBuilder){
System.out.println(e);
}
//String
String[] arrString=new String[]{"Hello1","Hello2","Hello3"};
for(String s:arrString){
s+="!";
}
for(String s:arrString){
System.out.println(s);
}
}
}
The results are as follows(Sorry I didn't add the results!):
Hello1!
Hello2!
Hello3!
Hello1
Hello2
Hello3
P.S.: I've taken out the printing line as a new for loop, it still works for StringBuilder but not String
On each iteration of the for-each loop the variable obtains a reference to the corresponding element of the array. In the case of for(StringBuilder e:arrStringBuilder) on the first iteration a new variable e of type StringBuilder will point to the same object as arrStringBuilder[0]. Then you call append using this reference, which performs operations on the object pointed by both references e and arrStringBuilder[0]. On the next iteration e will be assigned reference to arrStringBuilder[1], but the changes made in arrStringBuilder[0] will stay.
In the case of for(String s:arrString) on the first iteration a new variable s will be created pointing to arrString[0]. However, when you do s += '!' you actually perform s = s + '!', so you assign to this temporary variable s a reference to the new String object, which will contain Hello1!. This new object, however, is not related in any way to the original arrString[0] object, and at the start of the next iteration is just discarded. Your loop works like this:
for(int i = 0; i < 3; i++) {
// Create a temporary variable which points to the same object as arrString[i]
String s = arrString[i];
// Create a temporary object which keeps the result of concatenation of s and '!'
String temporary = s + '!';
// Replace the reference stored in s with the reference to the temporary object
s = temporary;
// Now there is no connection between s and arrString[i]
// And here we just discard both temporary objects 's' and 'temporary'
// arrString[i] object remains unchanged.
}
e.append("!"); is a call to a method, whose specific purpose is to modify e.
s+="!"; is not a method call. It is exactly equivalent to this:
s = s + "!";
This does not alter the state of any object. It merely creates a new String object (that is, a String whose text value is the old value of s plus "!"), and assigns that to the variable s. You are changing what s holds, but you didn’t modify the original String object that s used to hold.
It turns out there are no methods of String which will modify the String object, because Strings are immutable, by design. On the other hand, the StringBuilder class exists specifically to create and work with changeable text values.

Multiple string method chained in single code

I am working on this bit of code
public class SimpleStringTest {
public static void main(String args[])
{
String ints="123456789";
System.out.println(ints.concat("0").substring(ints.indexOf("2"),ints.indexOf("0")));
}
As per as my knowledge on java "When the multiple methods are chained on a single code statement, the methods execute from left to right" Then, Why is this bit of code throwing StringIndexOutOfBondsException?
Thanks in advance,
GPAR
Because Strings are immutable.
By invoking concat, you are not modifying ints, you are creating a new String.
Therefore by the time you invoke ints.indexOf("0"), ints is still equal to its former value and the indexOf invocation returns -1, which in turn will be the outer bound of your substring.
Try a counter-example with a mutable CharSequence such as StringBuilder:
StringBuilder ints = new StringBuilder("123456789");
System.out.println(ints.append("0").substring(ints.indexOf("2"),ints.indexOf("0")));
Output
23456789
Because ints.indexOf("0") is applied on the original String ints (not the one you concatenate).
Since there is no "0" indexOf("0") returns -1 and which throws the exception.
Your code is equivalent to this:
String ints="123456789";
int indexOne = ints.indexOf("2");
int indexTwo = ints.indexOf("0");
System.out.println(ints.concat("0").substring(indexOne, indexTwo));

Convert .toBinaryString into its complement

I do not know why I am getting an error at the yy.charAt(i) assignments. It says... Variable Expected... Not value.
static int subtract(int x,int y)
{
String yy=Integer.toBinaryString(y);
System.out.println(yy);
for(int i=0;i<yy.length();i++)
{
if(yy.charAt(i)==1)
{
yy.charAt(i)=0;
}
else
{
yy.charAt(i)
}
}
int t=Integer.parseInt(yy);
return(t);
}
You can't assign values to a string's index position, strings are immutable in Java. This will never work:
yy.charAt(i)=0;
If you need to modify a string, transform it to a char[] (using the toCharArray() method), modify the array and then build a new string from that array, using the String(char[]) constructor.
Alternatively, you could use a StringBuilder to modify the characters before returning a new string.
Use a StringBuilder instead.
The code would be almost identical to what you have now, except for these changes:
StringBuilder yy = new StringBuilder(Integer.toBinaryString(y));
...
yy.setChatAt(i, '0');
I think there are a few things that are not clear to you.
I think you mean the character '0' not the value 0.
The lines else { yy.charAt(i); } have absolutely no effect. You can simply omit them.
Strings are immutable in Java (i.e. they cannot be modified in place).
Even if they were, you're syntax is wrong. Something of the form class_name.method_name() is a call to a method of a class. It returns a value that you can store, it is not the same as a variable and trying to assign to a method call makes no sense at all.
To modify Strings in Java, the best way is probably to use a StringBuilder. You create a new StringBuilder using your String, make the necessary changes on that and then convert it back into a String.
So this would look something like this:
StringBuilder builder = new StringBuilder(yy); // StringBuilder from yy.
// rest of your code here
builder.setCharAt(i, '0');
// more code
yy = StringBuilder.toString(); // convert it back to a String.
Notice that even in a StringBuilder you have to call the appropriate method and pass in the value that you want to assign to it.

Converting an array list to a single string

I am working on a section of code for an assignment I am doing atm, and I am completely stuck with 1 little bit.
I need to convert the contents of an array list into a string, or the form of a string, which will be able to be imput into toString() in order for it to be printed to the screen.
public String toString(){
String full;
full = (this.name + this.address + "\n" + "Student Number = " + this.studentId);
for (int i = 0; i < cs.size(); i++) {
full.append(cs[i]);
return full;
The piece of above code is where i attempt to combine 3 varaibles and the contents of an array list into a single string with formatting.
Unfortunatly it creates an error "The type of the expression must be an array type but it resolved to ArrayList"
Thanks for any help.
Jake
cs is array list, so you have to do get operation, not [] (which is for array access)
It should be like:
full.append(cs.get(i));
Not
full.append(cs[i]);
EDIT: As assylis said, full should be StringBuilder not just String, because String doesn't support append() method.
StringBuilder full = new StringBuilder();
Apache Commons StringUtils has different varieties of join() methods that mean you don't have to write this yourself. You can specify the separator and even the prefix/suffix.
I would recommend you look at Apache Commons, not just for this but for lots of other useful stuff.
You are attempting to access an ArrayList as though it is a primitive array (using the square brackets around the index). Try using the get(int index) method instead.
i.e.,
cs.get(i);
You cannot index an ArrayList like an array, you need the get(index) method. Even better, use the enhanced for loop, since it's not recommended to index over a list, as the implementation may change to LinkedList.
I also suggest using a StringBuilder for efficiency:
public String toString() {
StringBuilder full = new StringBuilder();
full.append(this.name);
full.append(this.address);
full.append("\n");
full.append("Student Number = ");
full.append(this.studentId);
for (String s: cs)
full.append(s);
return full.toString();
}
Just use
"cs.get(i)" in place of "cs[i]".
as cs is an ArrayList not an Array.
and also use
full = full + cs.get(i); and not full.append(cs.get(i));
as String type dont have a append method.
Just a note, since you don't put any spacers between each element of the ArrayList it might be unreadable. Consider using Guava's Joiner class.
So instead of
for (...)
s.append(y);
if would be
a.append(Joiner.on(" ").join(yourList));
The Joiner is also more efficient than the for loop since it uses a StringBuilder internally.

Using an internal class to make a custom object, creating an array of that object, and access information in that object using Java

Code first questions later...
public class Program2
{
//The custom word object used when parsing the input file
class Word
{
public String wordname;
public int count;
public int uniqueWord = 0;
public Word(String word)
{
wordname = word;
count = 1;
}
public boolean wordExists(String word)
{
if (word == this.wordname)
{
this.count++;
return true;
}
else
{
return false;
}
}
public int getCount(Word word)
{
return this.count;
}
public String getName(Word word)
{
return this.wordname;
}
}
// The main method
public static void main(String[] args) throws IOException
{
//new array of words size 100
Word[] words = new Word[100];
//set the first word to bananna
Word words[0] = new Word("bananna");
//print bananna
System.out.print(getName(words[0]));
}
}
Ok, so with what I know about Java, the code above should let me make an array of words, set the first to "bananna", and print it out. I have little experience making a custom class like this, and I can't find a good resource to model. Also, I am not 100% sure I understand calling static/nonstatic methods, so I'm sure some of the errors are from that as well.
What the program should do eventually, as a reference for why I am doing this, I have to take information in from a file (delimited strings aka Words) and see if it already exists in the array of words (and increment that word's count if it does), if it doesn't then make a new word.
Errors I'm getting are here:
Program2.java:116: ']' expected
Word words[0] = new Word("bananna");
^
Program2.java:116: illegal start of expression
Word words[0] = new Word("bananna");
^
2 errors
Any other information that you need let me know. I'll be back to check this post in an hour. Thank you for any help you have!
Word words = new Word[100];
Your main problem I can see is that Word[100] is an Array type that holds Word objects. You'll need the words variable to be of type Word[], not just of type Word.
Regarding static and non-static, think of it this way: You've written a Word class, and then you can create as many Word objects as you like that belong to that class. When something is static, it means it belongs to the Word class, so it belongs to the definition of a word without belonging to any particular word. In contrast, something that is not static will belong to a particular Word object.
You have syntax errors when you try to create the array, you should have:
Word[] words = new Word[100];
If you want to invoke Word.newWord() without calling the method on an instance of the Word class, this method needs to be static.
The issue is with the way you are creating Array of Objects. You should declare the array of Class and then create objects:
//new array of words size 100
Word[] words = new Word[100];
//then Create objects
words[0] = new Word("apple");
Let's start with the first error message. This is telling you that Word[] and Word are incompatible types. The [] at the end tells you that this is an array of Word objects. In other words, Word words declares a reference to a single Word object. Whereas your use of new allocates an array of them. To fix this simply change to Word[] words.
I won't go into detail about the other error messages because they will likely change after you fix this one. Good luck with your Java!

Categories