package Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
public class Stringchar {
public static void main(String[] args) {
int count =0;
String s = "mmamma";
//System.out.println(s.length());
LinkedHashSet<Character> ch = new LinkedHashSet<Character>();
for (int i=0; i<s.length(); i++){
ch.add(s.charAt(i));
}
Iterator<Character> iterator = ch.iterator();
while(iterator.hasNext()){
Character st = (Character) iterator.next();
for (int k=0; k<s.length() ; k++){
if(charAt(k)== st){ // Why this charAt method is not working?
count = count+1;
}
if(count>1) {
System.out.println("Occurance of "+ st + "is" + count);
}
}
}
}
}
I am new to coding so I might be silly in asking this question. I have written a code where I am trying to print the occurrences and the number of the same of one character in a string using sets however I am facing some issues in doing so. Request you to help.
Here:
charAt(k);
is basically the same as
this.charAt(k);
In other words: you are trying to invoke a method on the class this code sits in.
I assume you intended to do someStringVariable.charAt(k) instead! ( sure, you meant s.charAt(), but s is a terrible, nothing telling name for a variable. Your variables are your pets, give them names that mean something!)
The method charAt is not static and need to be applied on a given String, if not how to know where to look for the xxth char ?
str.charAt(index);
Also, the print operation would better be after the for loop which counts the occurences, if not you'll have a print at each occurence
for (int k=0; k<s.length() ; k++){
if(s.charAt(k) == st){
count = count+1;
}
}
if(count>1) {
System.out.println("Occurance of "+ st + "is" + count);
}
I suppose you want to check, how often the Character appears in your string (String s = "mmamma";).
The charAt() method has to be applied on a String object, so you have to change the if condition from this:
if(charAt(k) == st)
To this:
if(s.charAt(k) == st)
The problem is that you are trying to get a character at a position of a character. When you create the variable st it is a character and will have a length of 1; there fore you are unable to get a charAt(index) there. Additionally this method of using the LinkedHashSet will not work because when you add those characters to the LinkedHashSet it will not add each character more than once. Instead you want an ArrayList.
This is probably not the most efficient solution but it will accomplish what you are trying to do with the HashSet
String s = "mmamma";
List<Character> characterList = new ArrayList<>();
LinkedHashSet<Character> characterLinkedHashSet = new LinkedHashSet<>();
for(char c : s.toCharArray()) {
characterLinkedHashSet.add(c);
characterList.add(c);
}
for (Character character : characterLinkedHashSet) {
int frequency = Collections.frequency(characterList, character);
System.out.println("The frequency of char " + character + " is " + frequency);
}
So what this does it is creates your LinkedHashSet as well as an ArrayList. The ArrayList stores all of the characters in a Collection and the LinkedHashSet stores only one instance of each Character. We can then loop over the HashSet and get the frequency inside the ArrayList
You have to correct your code like so,
while (iterator.hasNext()) {
int count = 0;
Character st = (Character) iterator.next();
for (int k = 0; k < s.length(); k++) {
if (s.charAt(k) == st) { // Why this charAt method is not working?
count++;
}
}
if (count > 1) {
System.out.println("Occurance of " + st + " is: " + count);
}
}
charAt method is available in String class hence you have to call it on a String reference. I have made few more improvements to the code too. Declare the count variable inside the while loop which is less error prone. Finally notice that I have moved the if statement away from the for loop since it gives some spurious intermediary results if it is kept inside the for loop.
This error occurs sometimes and sometimes it works properly. I really can't understand what the problem is.
int length = CitiesInfos.citiesOnTheRoad.length;
for (int i = 0; i < length; i++)
{
HashMap<String,String> temp=new HashMap<String, String>();
temp.put(FIRST_COLUMN, CitiesInfos.citiesOnTheRoad[i]);
if (CitiesInfos.roadWorkArrayList.get(i)!=null)
{
temp.put(SECOND_COLUMN, CitiesInfos.weatherArrayList.get(i).getCelcius() + ", " +
CitiesInfos.weatherArrayList.get(i).getWeatherStatus());
}
else
{
temp.put(SECOND_COLUMN, " ");
}
}
This is the line to which logCat directs. What can the problem be?
increment variable i loops from 0 to citiesOnTheRoad.length - 1, however, you also use i as an index to two other ArrayList variables: weatherArrayList and roadWorkArrayList, how are you certain they are the correct size?
I added a check that will prevent the crash you are receiving, but I caution you to take a closer look at your code instead of putting this band-aid on it.
int length = CitiesInfos.citiesOnTheRoad.length;
for (int i = 0; i < length; i++)
{
HashMap<String,String> temp=new HashMap<String, String>();
temp.put(FIRST_COLUMN, CitiesInfos.citiesOnTheRoad[i]);
if(i < CitiesInfos.roadWorkArrayList.size()
&& i < CitiesInfos.weatherArrayList.size()
&& CitiesInfos.roadWorkArrayList.get(i)!=null)
{
temp.put(SECOND_COLUMN, CitiesInfos.weatherArrayList.get(i).getCelcius() + ", " + CitiesInfos.weatherArrayList.get(i).getWeatherStatus());
}
else
{
temp.put(SECOND_COLUMN, " ");
}
}
As James Wierzba has mentioned, you are using the same control variable for the array lists in the loop and that is your problem.
You need to ensure that there are enough items before you try to retrieve an element.
A few suggestions:
it seems you are storing related data in two arrays, you are better of grouping this data together inside a class e.g. City.
You could then have the cities on the road array contain a number of city objects each storing information about the weather in that city.
I would also suggest that you do not have your arrays as public variables, you should have them as private or protected and use getters/setters to access them.
I'm writing a method that allows me to count how many times an element of type String shows up in a LinkedList of type Strings. my code shown below does not work. I keep getting index out of bounds in the line i commented on down below. Can't seem to find the bug
public int findDuplicate (LinkedList<String> e) {
int j = 1;
LinkedList<String> test = e;
while (!test.isEmpty()){
test = e;
String value = test.pop();
//Screws up here when i = 6
for(int i =0; i<=test.size() && test.get(i)!=null; i++){
String value3 = test.get(i);
if(e.get(i).equals(value) && i<=test.size()){
String value2 = test.get(i);
j++;
String Duplicate = e.get(i);
e.remove(i);
}
}
System.out.println(value + " is listed " + j + " times");
}
return j;
}
using hashmaps.. still doesn't work
public void findDuplicate (LinkedList e) {
Map<String,Integer> counts = new HashMap<String,Integer>();
while(!e.isEmpty()){
String value = e.pop();
for(int i =0; i<e.size(); i++){
counts.put(value, i);
}
}
System.out.println(counts.toString());
}
My code should go through the linked list find out how many times an element within the list appears and deletes duplicates from the list at the same time. Then prints the element and the number of times it appears in the list. I posted about this last night but didn't get a response yet. Sorry for the repost.
You are running off the end of the list. Change
for(int i =0; i<=test.size() && test.get(i)!=null; i++){
to
for(int i =0; i< test.size() && test.get(i)!=null; i++){
Valid indexes for a List (or an array) are 0 through size() - 1.
Regarding your hashmap example to count the duplicates:
#Test
public void countOccurrences() {
LinkedList<String> strings = new LinkedList<String>(){{
add("Fred");
add("Fred");
add("Joe");
add("Mary");
add("Mary");
add("Mary");
}};
Map<String,Integer> count = count(strings,new HashMap<String,Integer>());
System.out.println("count = " + count);
}
private Map<String, Integer> count(List<String> strings, Map<String, Integer> runningCount) {
if(strings.isEmpty()) {
return runningCount;
}
String current = strings.get(0);
int startingSize = strings.size();
while(strings.contains(current)) {
strings.remove(current);
}
runningCount.put(current, startingSize - strings.size());
return count(strings,runningCount);
}
If you want the original strings list preserved you could do
Map<String,Integer> count = count(new LinkedList<String>(strings),new HashMap<String,Integer>());
System.out.println("strings = " + strings);
System.out.println("count = " + count);
Check out google's guava collections which has a perfect class for maintaining a map and getting a count:
https://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap
Multiset<String> wordsMultiset = HashMultiset.create();
wordsMultiset.addAll(words);
// now we can use wordsMultiset.count(String) to find the count of a word
I hope you realize what the test = e statement is doing. After this statement executes both test and e refer to the same object.
If anyone of them modifies the list, the other sees it as they both are looking at the same object.
If this is not intended you need to clone the list before assigning it to another list reference.
This doesn't affect your out of bounds issue, but you are removing elements from your list while still evaluating it. If you remove an element, you should call i-- afterwards, or you skip the next entity (which is re-indexed) for evaluation.
Also of note regarding your code, I see you are trying to make a copy of your list, but standard assignment means test and e both point to the same instance. You need to use Collections.copy() see this SO thread on how to use the class.
Let's say I got this array:
String[][]array = new String[5][5];
array[2][2] = desperate;
Would it be possible to find whether
String s = "desperate"; - equals any array element without using a for loop, and without having to manually enter the row column combination of the array assigned the value "desperate"?
while loop instead of for loop
int i = 0;
int j = 0;
while (i < n)
{
while (j < m)
{
if (array[i][j].equals("..."))
{
///
}
j++;
}
i++;
}
Use enhanced-for loop: -
String [][] array = new String[2][2];
array[1][1] = "desperate";
array[0][1] = "despee";
array[1][0] = "despete";
array[0][0] = "dete";
for (String[] innerArr: array) {
for (String value: innerArr) {
if (value.equals("desperate")) {
System.out.println(value + " == desperate");
}
}
}
Output: - desperate == desperate
A better way that I would suggest is to use ArrayList<String> to store your items.. Then you can just call contains() method to check whether the list contains that element..
List<String> listString = new ArrayList<String>();
listString.add("desperate");
listString.add("despe");
if (listString.contains("desperate")) {
System.out.println("True");
}
Output: - True
Assuming that you can't (for any reasons) change your array to another collection type:
String[][]array = new String[5][5];
array[2][2] = "desperate";
public boolean contains(String str){
return new HashSet<String>((List<String>)Arrays.asList(array)).contains(str);
}
Better than transforming it to a List since HashSet's contains() method is O(1) and the one from List is O(n).
The only way to avoid using a loop (and it not clear why you would want to) is to use a Map which you pre-build with all the strings and indexes.
I run into this case a lot of times when doing simple text processing and print statements where I am looping over a collection and I want to special case the last element (for example every normal element will be comma separated except for the last case).
Is there some best practice idiom or elegant form that doesn't require duplicating code or shoving in an if, else in the loop.
For example I have a list of strings that I want to print in a comma separated list. (the do while solution already assumes the list has 2 or more elements otherwise it'd be just as bad as the more correct for loop with conditional).
e.g. List = ("dog", "cat", "bat")
I want to print "[dog, cat, bat]"
I present 2 methods the
For loop with conditional
public static String forLoopConditional(String[] items) {
String itemOutput = "[";
for (int i = 0; i < items.length; i++) {
// Check if we're not at the last element
if (i < (items.length - 1)) {
itemOutput += items[i] + ", ";
} else {
// last element
itemOutput += items[i];
}
}
itemOutput += "]";
return itemOutput;
}
do while loop priming the loop
public static String doWhileLoopPrime(String[] items) {
String itemOutput = "[";
int i = 0;
itemOutput += items[i++];
if (i < (items.length)) {
do {
itemOutput += ", " + items[i++];
} while (i < items.length);
}
itemOutput += "]";
return itemOutput;
}
Tester class:
public static void main(String[] args) {
String[] items = { "dog", "cat", "bat" };
System.out.println(forLoopConditional(items));
System.out.println(doWhileLoopPrime(items));
}
In the Java AbstractCollection class it has the following implementation (a little verbose because it contains all edge case error checking, but not bad).
public String toString() {
Iterator<E> i = iterator();
if (! i.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = i.next();
sb.append(e == this ? "(this Collection)" : e);
if (! i.hasNext())
return sb.append(']').toString();
sb.append(", ");
}
}
I usually write it like this:
static String commaSeparated(String[] items) {
StringBuilder sb = new StringBuilder();
String sep = "";
for (String item: items) {
sb.append(sep);
sb.append(item);
sep = ",";
}
return sb.toString();
}
There are a lot of for loops in these answers, but I find that an Iterator and while loop reads much more easily. E.g.:
Iterator<String> itemIterator = Arrays.asList(items).iterator();
if (itemIterator.hasNext()) {
// special-case first item. in this case, no comma
while (itemIterator.hasNext()) {
// process the rest
}
}
This is the approach taken by Joiner in Google collections and I find it very readable.
string value = "[" + StringUtils.join( items, ',' ) + "]";
My usual take is to test if the index variable is zero, e.g.:
var result = "[ ";
for (var i = 0; i < list.length; ++i) {
if (i != 0) result += ", ";
result += list[i];
}
result += " ]";
But of course, that's only if we talk about languages that don't have some Array.join(", ") method. ;-)
I think it is easier to think of the first element as the special case because it is much easier to know if an iteration is the first rather than the last. It does not take any complex or expensive logic to know if something is being done for the first time.
public static String prettyPrint(String[] items) {
String itemOutput = "[";
boolean first = true;
for (int i = 0; i < items.length; i++) {
if (!first) {
itemOutput += ", ";
}
itemOutput += items[i];
first = false;
}
itemOutput += "]";
return itemOutput;
}
I'd go with your second example, ie. handle the special case outside of the loop, just write it a bit more straightforward:
String itemOutput = "[";
if (items.length > 0) {
itemOutput += items[0];
for (int i = 1; i < items.length; i++) {
itemOutput += ", " + items[i];
}
}
itemOutput += "]";
Java 8 solution, in case someone is looking for it:
String res = Arrays.stream(items).reduce((t, u) -> t + "," + u).get();
I like to use a flag for the first item.
ArrayList<String> list = new ArrayList()<String>{{
add("dog");
add("cat");
add("bat");
}};
String output = "[";
boolean first = true;
for(String word: list){
if(!first) output += ", ";
output+= word;
first = false;
}
output += "]";
Since your case is simply processing text, you don't need the conditional inside the loop. A C example:
char* items[] = {"dog", "cat", "bat"};
char* output[STRING_LENGTH] = {0};
char* pStr = &output[1];
int i;
output[0] = '[';
for (i=0; i < (sizeof(items) / sizeof(char*)); ++i) {
sprintf(pStr,"%s,",items[i]);
pStr = &output[0] + strlen(output);
}
output[strlen(output)-1] = ']';
Instead of adding a conditional to avoid generating the trailing comma, go ahead and generate it (to keep your loop simple and conditional-free) and simply overwrite it at the end. Many times, I find it clearer to generate the special case just like any other loop iteration and then manually replace it at the end (although if the "replace it" code is more than a couple of lines, this method can actually become harder to read).
...
String[] items = { "dog", "cat", "bat" };
String res = "[";
for (String s : items) {
res += (res.length == 1 ? "" : ", ") + s;
}
res += "]";
or so is quite readable. You can put the conditional in a separate if clause, of course. What it makes idiomatic (I think so, at least) is that it uses a foreach loop and does not use a complicated loop header.
Also, no logic is duplicated (i.e. there is only one place where an item from items is actually appended to the output string - in a real world application this might be a more complicated and lengthy formatting operation, so I wouldn't want to repeat the code).
In this case, you are essentially concatenating a list of strings using some separator string. You can maybe write something yourself which does this. Then you will get something like:
String[] items = { "dog", "cat", "bat" };
String result = "[" + joinListOfStrings(items, ", ") + "]"
with
public static String joinListOfStrings(String[] items, String sep) {
StringBuffer result;
for (int i=0; i<items.length; i++) {
result.append(items[i]);
if (i < items.length-1) buffer.append(sep);
}
return result.toString();
}
If you have a Collection instead of a String[] you can also use iterators and the hasNext() method to check if this is the last or not.
If you are building a string dynamically like that, you shouldn't be using the += operator.
The StringBuilder class works much better for repeated dynamic string concatenation.
public String commaSeparate(String[] items, String delim){
StringBuilder bob = new StringBuilder();
for(int i=0;i<items.length;i++){
bob.append(items[i]);
if(i+1<items.length){
bob.append(delim);
}
}
return bob.toString();
}
Then call is like this
String[] items = {"one","two","three"};
StringBuilder bob = new StringBuilder();
bob.append("[");
bob.append(commaSeperate(items,","));
bob.append("]");
System.out.print(bob.toString());
Generally, my favourite is the multi-level exit. Change
for ( s1; exit-condition; s2 ) {
doForAll();
if ( !modified-exit-condition )
doForAllButLast();
}
to
for ( s1;; s2 ) {
doForAll();
if ( modified-exit-condition ) break;
doForAllButLast();
}
It eliminates any duplicate code or redundant checks.
Your example:
for (int i = 0;; i++) {
itemOutput.append(items[i]);
if ( i == items.length - 1) break;
itemOutput.append(", ");
}
It works for some things better than others. I'm not a huge fan of this for this specific example.
Of course, it gets really tricky for scenarios where the exit condition depends on what happens in doForAll() and not just s2. Using an Iterator is such a case.
Here's a paper from the prof that shamelessly promoted it to his students :-). Read section 5 for exactly what you're talking about.
I think there are two answers to this question: the best idiom for this problem in any language, and the best idiom for this problem in java. I also think the intent of this problem wasn't the tasks of joining strings together, but the pattern in general, so it doesn't really help to show library functions that can do that.
Firstly though the actions of surrounding a string with [] and creating a string separated by commas are two separate actions, and ideally would be two separate functions.
For any language, I think the combination of recursion and pattern matching works best. For example, in haskell I would do this:
join [] = ""
join [x] = x
join (x:xs) = concat [x, ",", join xs]
surround before after str = concat [before, str, after]
yourFunc = surround "[" "]" . join
-- example usage: yourFunc ["dog", "cat"] will output "[dog,cat]"
The benefit of writing it like this is it clearly enumerates the different situations that the function will face, and how it will handle it.
Another very nice way to do this is with an accumulator type function. Eg:
join [] = ""
join strings = foldr1 (\a b -> concat [a, ",", b]) strings
This can be done in other languages as well, eg c#:
public static string Join(List<string> strings)
{
if (!strings.Any()) return string.Empty;
return strings.Aggregate((acc, val) => acc + "," + val);
}
Not very efficient in this situation, but can be useful in other cases (or efficiency may not matter).
Unfortunately, java can't use either of those methods. So in this case I think the best way is to have checks at the top of the function for the exception cases (0 or 1 elements), and then use a for loop to handle the case with more than 1 element:
public static String join(String[] items) {
if (items.length == 0) return "";
if (items.length == 1) return items[0];
StringBuilder result = new StringBuilder();
for(int i = 0; i < items.length - 1; i++) {
result.append(items[i]);
result.append(",");
}
result.append(items[items.length - 1]);
return result.toString();
}
This function clearly shows what happens in the two edge cases (0 or 1 elements). It then uses a loop for all but the last elements, and finally adds the last element on without a comma. The inverse way of handling the non-comma element at the start is also easy to do.
Note that the if (items.length == 1) return items[0]; line isn't actually necessary, however I think it makes what the function does more easier to determine at a glance.
(Note that if anyone wants more explanation on the haskell/c# functions ask and I'll add it in)
It can be achieved using Java 8 lambda and Collectors.joining() as -
List<String> items = Arrays.asList("dog", "cat", "bat");
String result = items.stream().collect(Collectors.joining(", ", "[", "]"));
System.out.println(result);
I usually write a for loop like this:
public static String forLoopConditional(String[] items) {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < items.length - 1; i++) {
builder.append(items[i] + ", ");
}
if (items.length > 0) {
builder.append(items[items.length - 1]);
}
builder.append("]");
return builder.toString();
}
If you are just looking for a comma seperated list of like this: "[The, Cat, in, the, Hat]", don't even waste time writing your own method. Just use List.toString:
List<String> strings = Arrays.asList("The", "Cat", "in", "the", "Hat);
System.out.println(strings.toString());
Provided the generic type of the List has a toString with the value you want to display, just call List.toString:
public class Dog {
private String name;
public Dog(String name){
this.name = name;
}
public String toString(){
return name;
}
}
Then you can do:
List<Dog> dogs = Arrays.asList(new Dog("Frank"), new Dog("Hal"));
System.out.println(dogs);
And you'll get:
[Frank, Hal]
A third alternative is the following
StringBuilder output = new StringBuilder();
for (int i = 0; i < items.length - 1; i++) {
output.append(items[i]);
output.append(",");
}
if (items.length > 0) output.append(items[items.length - 1]);
But the best is to use a join()-like method. For Java there's a String.join in third party libraries, that way your code becomes:
StringUtils.join(items,',');
FWIW, the join() method (line 3232 onwards) in Apache Commons does use an if within a loop though:
public static String join(Object[] array, char separator, int startIndex, int endIndex) {
if (array == null) {
return null;
}
int bufSize = (endIndex - startIndex);
if (bufSize <= 0) {
return EMPTY;
}
bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length()) + 1);
StringBuilder buf = new StringBuilder(bufSize);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}