Counting the number of unique letters in a string - java

I have to write code that counts how many unique letters are in a string:
e.g
"aabbcdefff"
This will return 6 as there are 6 different letters in the string. Currently I have the code:
String letters = ("aabbcdefff");
char temp = ' ';
for (int i = 0; i < letters.length(); i++){
temp = inp.charAt(i);
if (temp != ' ') { //doesnt count spaces as letters
alphabetSize = alphabetSize+1;
for (int j = 0; j < inp.length(); j++){
tempInp = tempInp.replace(temp,' ');
}
}
}
The idea of this code is that it should when detecting a letter, replace all instances of it with a space. When i run this code however, it just gives me the length of the string. What am i doing wrong? Is there another more elegant way to do this?
Thanks for your help.

You are fine by just using a Set.
Loop over your string, and add each letter to your set. afterwards, check length of your set, and your done.

It's a one-liner with Java 8 streaming API:
long numberOfDistinctChars = s.chars().distinct().count()

You can easily find it using Linq service.
Please add using System.Linq; Namespace.
string str = "TestTest";
int cnt = str.ToLower().ToCharArray().Where(w => w != ' ').Distinct().Count();

You can do it easily by using Java collection (Set).
Set<Character> result = new HashSet<Character>();
String letters = ("aabbcdefff");
for (int i = 0; i < letters.length(); i++){
result.add(letters.charAt(i));
}
Your final result is in result set and it is always unique.
Reference: http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
Thanks.

One way of doing this would be converting the string to an array and then using the following method:
String s = "aabbcdefff";
char[] charArray = s.toCharArray();
ArrayList<Character> al = new ArrayList<Character>();
for(char c : charArray){
if(al.contains(c)){
al.remove((Character)c);
}else{
al.add(c);
}
}
What ever is left in the array list 'al' are duplicates. The advantage of this method is that it has O(n) runtime

Related

Remove certain chars in-place

As far as I know, in C we can modify a char-array in-place and then append the \0 to make the char-array shorter. I am wondering how that's done in Java.
Assume we want to remove the spaces from a char-array in Java.
char[] str = new String("cat love dogs").toCharArray();
for(int i = 0; i < str.length; i++) {
if(str[i] == ' ')
str[i] = '';
}
This does not seem to work.
EDIT: I already know about built-in functions to replace some chars with another in a string. I am not asking that. Curious to modify a char-array in-place with O(1) extra space.
well the best solution i can see is remove all spaces from your string first then get the chars from it :
String myString = new String("cat love dogs").replaceAll("\\s+", "");
// \\s+ is the regex for sapces
// myString becomes => catlovedogs
char[] str = myString.toCharArray();
As String is immutable you may use a StringBuilder class:
StringBuilder sb = new StringBuilder("cat love dogs");
for(int i = 0; i < sb.length(); i++) {
if(sb.charAt(i) == ' ') {
sb.deleteCharAt(i);
i--;
}
}
char[] str = sb.toString().toCharArray();
Now as far as space is concerned String class in Java is immutable!
Thus you cannot do anything in place there.
But you can use StringBuilder which is immutable.
Code:
StringBuilder stringBuilder = new StringBuilder("cat love dogs");
for(int i = 0; i < stringBuilder.length(); i++) {
if (sb.charAt(i) == ' ')
sb.deleteCharAt(i);
}
char[] str = stringBuilder.toString().toCharArray();
Or if you want to do it just using the char array itself its not possible as char arrays are not dynamic by themselves.
But here is what you could do:
char[] str = new String("cat love dogs").toCharArray();
int last = 0;
for(int i = 0; i < str.length; i++) {
if(str[i] == ' '){
str = ArrayUtils.remove(str, i);
}
}
System.out.println(new String(str));
System.out.println(new String(str).length());
Output:
catlovedogs
11
For for this you need to import org.apache.commons.lang3.ArrayUtils
If you are not concerned about space:
In Java we can just set the character value to 0!
Here is the modified code:
char[] str = new String("cat love dogs").toCharArray();
for(int i = 0; i < str.length; i++) {
if(str[i] == ' ')
str[i] = 0;
}
System.out.println(new String(str));
Here is the output:
catlovedogs
I think the best way to do this is by creating a duplicate array of chars, where you copy every character besides the spaces and then return the new array. Here is how the code might look like:
char[] str = new String("cat love dogs").toCharArray();
List<Character> duplicate = new ArrayList<>();
for(int i = 0; i < str.length; i++) {
if(str[i] != ' ') {
duplicate.add(str[i]);
}
}
it's better to use ArrayList because you don't really know the final size of the array and this way you can go only as big as needed.

Issues with char array and replacing words

I am attempting to iterate through characters for a "curse word filter", there is a config file that defines what the curse words will be replaced with. Sometimes my code is grabbing the last letter/number of the key and putting it at the end of the key string.
Tried doing this in a few different ways, the whole attempt of this is to avoid case sensitivity and find every possible attempt at beating it.
here's an example of it breaking - http://prntscr.com/nqyirl
public void onChat(AsyncPlayerChatEvent event)
{
String originalMessage = event.getMessage();
ArrayList<String> swearWords = new ArrayList<>();
for (String key : getConfig().getConfigurationSection("replace-words").getKeys(false))
swearWords.add(key);
ArrayList<Character> charArrayList = new ArrayList<>();
for (char c : originalMessage.toCharArray())
charArrayList.add(c);
for (String swearWord : swearWords)
{
Bukkit.broadcastMessage(swearWord);
int startIndex;
if ((startIndex = originalMessage.toLowerCase().indexOf(swearWord)) != -1)
{
int endIndex = startIndex + swearWord.length();
for (int i = startIndex; i < endIndex; i++)
{
charArrayList.remove(startIndex);
charArrayList.trimToSize();
}
char[] replaceWith = getConfig().getString("replace-words." + swearWord).toCharArray();
Bukkit.broadcastMessage(new String(replaceWith));
for (int i = 0; i < replaceWith.length; i++) {
char c = replaceWith[i];
charArrayList.add(startIndex + i, c);
}
}
}
final char[] array = new char[charArrayList.size()];
for (int i = 0; i < array.length; i++)
array[i] = charArrayList.get(i);
event.setMessage(new String(array));
}
Config File -
#configurables, enjoy
replace-words:
test1234: testo22345566
It should be replacing test1234 with testo22345566, instead it adds a 4 on the end. Making it - testo223455664. Example here - http://prntscr.com/nqyirl
EDIT: I've had a break through, anything over 7 characters breaks it.
you probably just don't remove the last symbol. my guess is that changing
for
(int i = startIndex; i < endIndex; i++)
to
for
(int i = startIndex; i <= endIndex; i++)
should fix the problem
why changing it into char[]?
a String has internal a char[], but gives you much more and easier replace functions.
for example originalMessage.replaceAll("test1234","testo22345566")
would replace all test1234 occurences with testo22345566
info about that method:https://www.javatpoint.com/java-string-replaceall
this makes it possible to add regex filters instead of a one to one replace configuration. (the replaceAll function on string uses regex for its searching of occurences)
for example
#configurables, enjoy
replace-words:
(?i)test[0-9]{4}: testo22345566
would in case of the repleaceAll function on string work on all caseinsensitive values followed by 4 numbers
be aware if the swearword replacer can recreate another swearword it could be needed to pass multiple times over this replacer.
edit: modification because of some comments:
you could also just use your config, but still use the originalMessage.replaceAll(wordOfTheConfigList,replacementword)
String newMessage = originalMessage;
String inBetweenChars = "([\s\._]*)";
for (String swearWord : swearWords){
String searchWord = "(?i)"+inBetweenChars+String.join(inBetweenChars,swearWord) + inBetweenChars;
String replaceWith = getConfig().getString("replace-words." + swearWord)
newMessage = newMessage.replaceAll(searchWord,replaceWith))
}
event.setMessage(newMessage);
with this answer you can only use normal text in the config, so no [0-9] or other regex features, as this would result in strange [\s0\s-\s9\s] kinda things (wont work) but as you weren't using regex in that config I hope that's not a real problem.

How to reverse a String after a comma and then print the 1st half of the String Java

For example String grdwe,erwd becomes dwregrdwe
I have most of the code I just have trouble accessing all of ch1 and ch2 in my code after my for loop in my method I think I have to add all the elements to ch1 and ch2 into two separate arrays of characters but I wouldn't know what to initially initialize the array to it only reads 1 element I want to access all elements and then concat them. I'm stumped.
And I'd prefer to avoid Stringbuilder if possible
public class reverseStringAfterAComma{
public void reverseMethod(String word){
char ch1 = ' ';
char ch2 = ' ';
for(int a=0; a<word.length(); a++)
{
if(word.charAt(a)==',')
{
for(int i=word.length()-1; i>a; i--)
{
ch1 = word.charAt(i);
System.out.print(ch1);
}
for (int j=0; j<a; j++)
{
ch2 = word.charAt(j);
System.out.print(ch2);
}
}
}
//System.out.print("\n"+ch1);
//System.out.print("\n"+ch2);
}
public static void main(String []args){
reverseStringAfterAComma rsac = new reverseStringAfterAComma();
String str="grdwe,erwd";
rsac.reverseMethod(str);
}
}
You can use string builder as described here:
First split the string using:
String[] splitString = yourString.split(",");
Then reverse the second part of the string using this:
splitString[1] = new StringBuilder(splitString[1]).reverse().toString();
then append the two sections like so:
String final = splitString[1] + splitString[0];
And if you want to print it just do:
System.out.print(final);
The final code would be:
String[] splitString = yourString.split(",");
splitString[1] = new StringBuilder(splitString[1]).reverse().toString();
String final = splitString[1] + splitString[0];
System.out.print(final);
Then, since you are using stringbuilder all you need to do extra, is import it by putting this at the top of your code:
import java.lang.StringBuilder;
It appears you currently have working code, but are looking to print/save the value outside of the for loops. Just set a variable before you enter the loops, and concatenate the chars in each loop:
String result = "";
for (int a = 0; a < word.length(); a++) {
if (word.charAt(a) == ',') {
for (int i = word.length() - 1; i > a; i--) {
ch1 = word.charAt(i);
result += ch1;
}
for (int j = 0; j < a; j++) {
ch2 = word.charAt(j);
result += ch2;
}
}
}
System.out.println(result);
Demo
Let propose a solution that doesn't use a StringBuilder
You should knoz there is no correct reason not to use that class since this is well tested
The first step would be to split your String on the first comma found (I assumed, in case there is more than one, that the rest are part of the text to reverse). To do that, we can you String.split(String regex, int limit).
The limit is define like this
If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n and the array's last entry will contain all input beyond the last matched delimiter.
If n is non-positive then the pattern will be applied as many times as possible and the array can have any length.
If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
Example :
"foobar".split(",", 2) // {"foobar"}
"foo,bar".split(",", 2) // {"foo", "bar"}
"foo,bar,far".split(",", 2) // {"foo", "bar,far"}
So this could be used at our advantage here :
String text = "Jake, ma I ,dlrow olleh";
String[] splittedText = text.split( ",", 2 ); //will give a maximum of a 2 length array
Know, we just need to reverse the second array if it exists, using the simplest algorithm.
String result;
if ( splittedText.length == 2 ) { //A comma was found
char[] toReverse = splittedText[1].toCharArray(); //get the char array to revese
int start = 0;
int end = toReverse.length - 1;
while ( start < end ) { //iterate until needed
char tmp = toReverse[start];
toReverse[start] = toReverse[end];
toReverse[end] = tmp;
start++; //step forward
end--; //step back
}
result = new String( toReverse ) + splittedText[0];
}
This was the part that should be done with a StringBuilder using
if ( splittedText.length == 2 ){
result = new StringBuilder(splittedText[1]).reverse().toString() + splittedText[0];
}
And if there is only one cell, the result is the same as the original text
else { //No comma found, just take the original text
result = text;
}
Then we just need to print the result
System.out.println( result );
hello world, I am Jake

Comparing string character by character in Java

How to compare individual character that is stored in a variable in Java?
String value = "abaabb";
Now how can I know that abaabb consist of only a and b in it and no other characters like c, d, ...
For this I want a way to compare individual characters in abaabb.
You can use .charAt() method:
String x="aabbbb";
for (int i = 0; i < x.length(); i++) {
if(x.charAt(i)=='a' || x.charAt(i)=='b') {
System.out.println("a or b");
}
}
You could use String#matches with Regular Expression:
boolean valid = "abaabb".matches("[ab]+");
easiest solution:
String value = "abaabb";
Set<Character> letters = new HashSet<Character>();
for(int i = 0; i < value.length(); i++){
letters.add(value.charAt(i));
}
//Edit
#Trincot
In set we collect unique characters in string, then we can build second collection with letters to check if only 'a' and 'b' are present
Set<Character> check = new HashSet<>();
check.add('a');
check.add('b');
letters.removeAll(check);
System.out.println(letters.isEmpty());

Java String. Replace list of chars by other chars list

I have String variable with value- f.e.:
this is test-str-ing_łóśżćń.
And I would like replace this chars:
, -, ł,ó,ś,ż,ć,ń
with those:
_,_,l,o,s,z,c,n.
And I mean here, that if parser will found f.e.: char - (which is second in first list) should be replaced with char that is in the same position/place in second list, which in this example is: _.
The char ó should be replaced with char o.
The char ń should be replaced with char n.
In my case the list of characters to replace is quite long and parsing in loop for each char to replace would not be enought efficient.
I know method replaceAll(). but it only accept one in String and one out String
So I am looking for method, that will allow me to work on arrays/list of Strings instead of single String.
Please give me some help.
Use java.text.Normalizer to Decompose accented letters in base letter plus "combining diacritical marks."
String base = Normalizer.normalize(accented, Form.NFKD)
.replaceAll("\\p{M}", "");
This does a decompose (D) normalization, and then removes Marks.
Some replacements still needed.
char[] out = new char[src.length()];
for( j ...){
inputChar = src.charAt(j);
for (int i = 0; i < convertChars.length; i++) {
if (inputChar == convertChars[i]) {
inputChar = toChars[i];
}
}
}
out[j] = inputChar ;
}
out2 = new String(out);
Extracted from bigger code without IDE, not tested. Loop (I hope) don't allocate objects and should not degrade speed.
Make a static lookup table:
private static char[] substitutions = new char[65536];
static {
// Initialize
for (char c = 0; c < substitutions.length; c++) {
substitutions[c] = c;
}
// Now add mappings.
substitions['-'] = '_'; // Map source->target character
... // Add the rest
}
// LATER IN Code
char[] stringChars = inputString.toCharArray();
for (int i = 0; i < stringChars.length; i++) {
stringChars[i] = substitutions[stringChars[i]];
}
outputString = new String(stringChars);

Categories

Resources