This question already has answers here:
What is the easiest/best/most correct way to iterate through the characters of a string in Java?
(16 answers)
Closed 4 years ago.
I need a Iterator<Character> from a String object. Is there any available function in Java that provides me this or do I have to code my own?
One option is to use Guava:
ImmutableList<Character> chars = Lists.charactersOf(someString);
UnmodifiableListIterator<Character> iter = chars.listIterator();
This produces an immutable list of characters that is backed by the given string (no copying involved).
If you end up doing this yourself, though, I would recommend not exposing the implementation class for the Iterator as a number of other examples do. I'd recommend instead making your own utility class and exposing a static factory method:
public static Iterator<Character> stringIterator(final String string) {
// Ensure the error is found as soon as possible.
if (string == null)
throw new NullPointerException();
return new Iterator<Character>() {
private int index = 0;
public boolean hasNext() {
return index < string.length();
}
public Character next() {
/*
* Throw NoSuchElementException as defined by the Iterator contract,
* not IndexOutOfBoundsException.
*/
if (!hasNext())
throw new NoSuchElementException();
return string.charAt(index++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
It doesn't exist, but it's trivial to implement:
class CharacterIterator implements Iterator<Character> {
private final String str;
private int pos = 0;
public CharacterIterator(String str) {
this.str = str;
}
public boolean hasNext() {
return pos < str.length();
}
public Character next() {
return str.charAt(pos++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
The implementation is probably as efficient as it gets.
for (char c : myString.toCharArray()) {
}
Stealing from somebody else in another answer, this is probably the best direct implementation (if you're not going to use guava).
/**
* #param string
* #return list of characters in the string
*/
public static List<Character> characters(final String string) {
return new AbstractList<Character>() {
#Override
public Character get(int index) {
return string.charAt(index);
}
#Override
public int size() {
return string.length();
}
};
}
CharacterIterator it = new StringCharacterIterator("abcd");
// Iterate over the characters in the forward direction
for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next())
// Iterate over the characters in the backward direction
for (char ch=it.last(); ch != CharacterIterator.DONE; ch=it.previous())
Short answer:
No, you have to code it.
Long answer:
List and Set both have a method for obtaining an Iterator (there are a few other collection classes, but probably not what your looking for). The List and Set interfaces are a part of the Collections Framework which only allow for adding/removing/iterating Objects like Character or Integer (not primitives like char or int). There is a feature in Java 1.5 called auto-boxing that will hide this primitive to Object conversion but I don't recommend it and it won't provide what you want in this case.
An alternative would be to wrap the String in a class of your own that
implements Iterator<Character>
but that might be more work than it is worth.
Here is a code snippet for doing what you want:
String s = "";
List<Character> list = new ArrayList<Character>(s.length());
for (int i = 0; i < s.length(); i++) {
// note that Character.valueOf() is preferred to new Character()
// you can omit the Character.valueOf() method
// and Java 1.5+ will auto-box the primitive into an Object
list.add(Character.valueOf(s.charAt(i)));
}
Iterator<Character> iterator = list.iterator();
No direct way. Not difficult to code, though:
public static Iterator<Character> gimmeIterator(final String x) {
Iterator<Character> it = new Iterator<Character>() {
String str = x == null ? "" : x;
int pos = -1; // last read
public boolean hasNext() { return(pos+1 < str.length()); }
public Character next() { pos++; return str.charAt(pos); }
public void remove() {
throw new UnsupportedOperationException("remove unsupported for this iterator");
}
};
return it;
}
This can be done with a little help from Apache Commons Lang (if you don't want to use Guava, and want a true java.util.Iterator.
private static Iterator<Character> iterator(String string) {
return Arrays.asList(ArrayUtils.toObject(string.toCharArray())).iterator();
}
With java 8 or newer you can use the stream facility. With the chars() method you can access an IntStream. The IntStream supports the method iterator() that returns an OfInt iterator. OfInt implements Iterator<Integer>.
String str = "foobar";
OfInt ofit = str.chars().iterator();
Iterator<Integer> it = ofit;
It is not a perfect answer, since you asked for Iterator<Character>.
Btw: With str.codePoints() you can also access a code point IntStream.
Not sure if there is a more direct way but you could do something like;
Arrays.asList(string.toCharArray()).iterator();
Scratch that; Arrays.asList doesn't do what I seem to remember it doing.
Edit 2: Seems like it last worked this way in 1.4
The Iterator iterate over a collection or whatever implements it. String class does nost implement this interface. So there is no direct way.
To iterate over a string you will have to first create a char array from it and then from this char array a Collection.
This feels dirty, but you could use Scanner with empty string delimiter:
Scanner scanner = new java.util.Scanner(myInput).useDelimiter("");
Scanner implements Iterator, so scanner is now an Iterator of length-1 strings, which is close.
To continue with the (very?) dirty, in Java 8 you can then do this to succinctly iterate by chars:
for (String s: (Iterable<String>)() -> scanner) {
char c = s.charAt(0);
System.out.println(c);
}
For details on why () -> scanner works (and why it may be dangerous, though not in this use case), see Explain how this lambda can be assigned to an Iterable.
Related
Ok so the goal of the class is to override the two methods inside of the Enumeration object class. I believe my hasNextElement() method should work, any pointers on that would be appreciated. I, however, am having troubles with the nextElement() method. Excuse the improper commenting throught the class but the goal of nextElement() is to return one character at a time. I figured its just a simple loop but netBeans keeps giving me incompatible dataTypes, which makes sense because its a String method not a Char method. So I change it to char and I get
nextElement() in StringEnumeration cannot implement nextElement() in Enumeration return type char is not compatible with String where E is a type-variable:
Any help would be greatly appreciated. Do remember I am a beginner programmer so I may have done something wrong that is easily fixable.
public class StringEnumeration implements Enumeration<String> {
public String value;
public StringEnumeration(String initialValue) throws InvalidStringException {
if (initialValue == null || initialValue.length() == 0) {
throw new InvalidStringException("initialValue is either null or 0");
}
this.value = initialValue;
}
#Override
public boolean hasMoreElements() {
return value.length() != 0 || value != null;
}
#Override
public String nextElement() {
StringBuffer test = new StringBuffer(value);
for (int i = 0; i < value.length(); i++) {
return test.charAt(i);
}
}
}
The easiest is to keep the index you're at as a variable in the enumeration:
// we return characters
public class StringEnumeration implements Enumeration<Character> {
// the value
private String value;
// current index
private int idx=0;
public StringEnumeration(String initialValue) throws IllegalArgumentException {
if (initialValue == null || initialValue.length() == 0) {
throw new IllegalArgumentException("initialValue is either null or 0");
}
this.value = initialValue;
}
#Override
public boolean hasMoreElements() {
// can we still read
return idx<value.length();
}
#Override
public Character nextElement() {
// get current char and increment index
return value.charAt(idx++);
}
}
Your implementation has several problems.
First, in Enumeration<E> the E is not the type the enumeration is working on. It's the type that the nextElement() method is supposed to return. So an Enumeration<String> has a nextElement() method that returns String. But your implementation returns the result of charAt() - a method that returns the primitive char, not a String! You either have to return some sort of string (maybe a single-char string like "m") or a Character (because you can't make E a primitive type like char).
The next problem is that your hasNextElement() method is not actually correct. An Enumeration is intended to give you one element (character, in your case) of the data at a time, and each time you call nextElement() it moves ahead towards the end of the data. so hasNextElement() has to return true based on whether or not there is still another element to go through. Your implementation, however, will always return true for the same string. It will not give an indication when to stop calling nextElement().
Last, your nextElement() somehow thinks that it's going to return all the elements at the same time. This cannot work. An Enumeration can only give one element each time you call nextElement(). So using a loop inside it makes no sense. The proper way to do this is to keep state inside the Enumeration object, say a variable named next, that indicates where the next element is. Each time the caller calls nextElement(), you take that element, advance next, and return the element. One element at a time, no loops. The actual loop will be created by whoever is using the Enumeration, not by the Enumeration itself.
It is also this next field (or whatever you want to call it) that can help you to create a proper hasMoreElements() method. If the next reaches beyond the end of the string, hasMoreElements() has to return false, and nextElement() has to throw NoSuchElementException.
I think what you intend to implement is an Iterator<T> over the characters of a given string:
public class StringEnumeration implements Iterator<Character> {
private final String value;
private int index = 0;
public StringEnumeration(String initialValue) {
if(initialValue == null) {
this.value = "";
} else {
this.value = initialValue;
}
}
#Override
public boolean hasNext() {
return index < value.length();
}
#Override
public Character next() {
try {
return test.charAt(this.index);
} finally {
this.index++;
}
}
#Override
public void remove() {
//can be done. Necessary?
}
}
(You can use an Enumeration<T> by simply replacing Iterator<Character> with Enumeration<Character>; and hasNext and next with hasMoreElements and nextElement and remove the remove method.
This iterator considers that the null String and the empty string "" contain both zero characters.
An iterator needs to store a state in the iteration process: the index of the character to enumerate. Initially the index is set to 0. After each item, the index is incremented.
Furthermore the test is simply whether the value has already reached the end of the String.
The main problem with your code is the following:
#Override
public String nextElement() {
StringBuffer test = new StringBuffer(value);
for (int i = 0; i < value.length(); i++) {
return test.charAt(i);
}
}
You use a for-loop but with a return statement. If you thus ask for the nextElement Java will start iterating and immediately return the first character. Furthermore this probably won't compile since the Java compiler can't figureout test has at least one element and thus it is possible that the for loop is never executed.
Other advice
Please always make fields private. By making fields public, a class can no longer guarantee the consistency of its state.
Furthermore Iterator is a modern version of Enumeration (although there is some discussion about this).
//know acess modifiers well...
private String value;
private Integer currentPosition;
public StringEnumeration(String initialValue) throws InvalidStringException {
if (initialValue == null || initialValue.length() == 0) {
throw new InvalidStringException("initialValue is either null or 0");
}
this.value = initialValue;
}
//you would return false when the list is empty OR the current position is
//past the end of the string
#Override
public boolean hasMoreElements() {
return value.length() != 0 || currentPosition < value.length();
}
//you would return the character at the current position
#Override
public char nextElement() {
return value.charAt(currentPosition++);
}
With the use of below code, I am finding out which datacenter I am in and it is working fine..
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
private static DatacenterEnum compareLocation() {
String ourhost = getHostName();
for (DatacenterEnum dc : values()) {
String namepart = "." + dc.name().toLowerCase() + ".";
if (ourhost.indexOf(namepart) >= 0) {
return dc;
}
}
return null;// I don't want to do this now.
}
}
But it might be possible that it is not able to find any datacenter, so currently I am returning null.
Is there any direct way or a single line command by which I can return randomly either DC1 or DC2 or DC3 in the ENUM instead of returning null?
I know one way is to make a list of string and then randomnly select any integer between 0 to 2 inclusive and then find the string. But it is too much code, actually it's not but just trying to see is there any other way we can do this?
Any simple and direct way which I can use in the ENUM directly?
Here's the one line:
return DataCenterEnum.values()[new Random().nextInt(3) + 1)];
For those who require tighter control on their code, here's a safer version, which does not depend on the order of the enum instances:
return new DataCenterEnum[]{DC1, DC2, DC3}[new Random().nextInt(3)];
Here is a generic solution that will work for any enumeration.
Convenience method for single exclusion:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, E exclude) {
return getRandom(aEnum, Collections.singletonList(exclude));
}
Generic method that works with one or more exclusions:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, List<E> exclude){
//Convert set of enums into a list
List<E> enums = new ArrayList<E>(EnumSet.allOf(aEnum));
//Remove items from the list that you want to exclude
enums.removeAll(exclude);
int size = enums.size();
if(size != 0){
//Get random enum
int randomIndex = new Random().nextInt(size);
return enums.get(randomIndex);
} else {
throw new IllegalArgumentException("Empty Enumeration after excludes");
}
}
For your example you could call
EnumUtil.getRandom(DatacenterEnum.class, DatacenterEnum.DEV);
You could use the values() method, which returns an array. Then just use Math.random() to return a random instance.
Here is an example:
public static void main (String[] args) {
String[] arr = {"DEV","DC1","DC2","DC3"}; //returned by Enum.values(), you get the idea
String randElement = arr[(int) ((Math.random() * 3) +1)];
System.out.println(randElement);
}
Basically it boils down to generating a random number between 1 and n :)
I am trying to sort an arraylist by string length, i know of implementing Comparator, but i was wondering if this could be done within my function, without adding any extra classes or methods? Ideally I want to output them shortest to longest, but that I can do!
Here is a snippet of the method i would like to implement the comparator with.
public static void sCompare(BufferedReader r, PrintWriter w) throws IOException {
ArrayList<String> s= new ArrayList<String>();
String line;
int n = 0;
while ((line = r.readLine()) != null) {
s.add(line);
n++;
}
//Collections.sort(s);
Iterator<String> i = s.iterator();
while (i.hasNext()) {
w.println(i.next());
}
}
Thanks in advance for any input!
I don't see anything wrong with implementing the Comparator interface.
If your only concern is doing everything in the function, you could use an anonymous implementation. Something along the lines of :
Collections.sort(s, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
(that would replace you current line //Collections.sort(s);)
PS : you never use the value of n.
PPS: You may have to invert o1 and o2 depending of the order you want in the return statement.
Another example of implementing an interface with an anonymous class
I'm going to assume by "class" you mean "top level class", thus allowing the use of an anonymous class:
Collections.sort(s, new Comparator<String>() {
public int compare(String a, String b) {
// java 1.7:
return Integer.compare(a.length(), b.length());
// java 1.6
return a.length() - b.length();
}
});
public class Anagram {
public static void main(String[] args) {
String a = "Despera tion-".toLowerCase();
String b = "A Rope Ends It".toLowerCase();
String aSorted = sortStringAlphabetically(a);
String bSorted = sortStringAlphabetically(b);
if(aSorted.equals(bSorted)){
System.out.println("Anagram Found!");
}else{
System.out.println("No anagram was found");
}
}
public static String sortStringAlphabetically(String s) {
char[] ca = s.toCharArray();
int cnt = 0;
ArrayList al = new ArrayList();
for (int i = 0; i < ca.length; i++) {
if (Character.isLetter(ca[cnt]))
al.add(ca[cnt]);
cnt++;
}
Collections.sort(al);
return al.toString();
}
}
As a learner, I hacked up this boolean Anagram checker. My chosen solution was to create a sortStringAlphabetically method seems to do just too much type-juggling String -> chars[] -> ArrayList ->String - given that I do just want to compare 2 strings to test whether one phrase is an anagram of another - could I have done it with less type-juggling?
ps The tutors solution was a mile away from my attempt, and probably much better for a lot of reasons - but I am really trying to get a handle on all the different Collection types.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/doc/src-html/de/hska/java/exercises/arrays/Anagram.html#line.18
EDIT
FTW here is the original challenge, I realise I wandered away from the solution.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/arrays.html
My initial kneejerk reaction was to simply work though array a, knocking out those chars which matched with array b - but that seemingly required me to rebuild the array at every iteration - Many thanks for all your efforts to educate me.
There are different ways to improve this, if you go with this algorithm.
First, you don't necessarily need to create a character array. You can use String.charAt() to access a specific character of your string.
Second, you don't need a list. If you used a SortedMultiSet or a SortedBag, you could just add things in sorted order. If you write a function that creates the SortedMultiSet from your string, you could just compare the sets without rebuilding the string.
Note: I don't know what libraries you're allowed to use (Google and Apache have these types), but you can always 'brew your own'.
Also, make sure to use generics for your types. Just defining ArrayLists is pretty risky, IMHO.
You could just sort the string without using a list:
public static String sortStringAlphabetically(String s) {
String lettersOnly = s.replaceAll("\\W", "");
char[] chars = lettersOnly.toCharArray();
Arrays.sort(chars);
return new String(chars);
}
N.B. I haven't actually tried running the code.
Your algorithm, but shorter (and yet, slower). The "type-juggling" is done "implicitly" in Java's various library classes:
public static boolean isAnagram(String a, String b) {
List<String> listA = new ArrayList<String>(Arrays.asList(
a.toLowerCase().replaceAll("\\W", "").split("")));
List<String> listB = new ArrayList<String>(Arrays.asList(
b.toLowerCase().replaceAll("\\W", "").split("")));
Collections.sort(listA);
Collections.sort(listB);
return listA.equals(listB);
}
Optionally, replace the \W regular expression to exclude those letters that you don't want to consider for the anagram
public class Anagram {
public static void main(String[] args) throws Exception {
String s1 = "Despera tion-";
String s2 = "A Rope Ends It";
anagramCheck(s1, s2);
}
private static void anagramCheck(String s1, String s2) {
if (isAnagram(s1, s2)) {
System.out.println("Anagram Found!");
} else {
System.out.println("No anagram was found");
}
}
private static boolean isAnagram(String s1, String s2) {
return sort(s1).equals(sort(s2));
}
private static String sort(String s) {
char[] array = s.replaceAll("\\W", "").toLowerCase().toCharArray();
Arrays.sort(array);
return new String(array);
}
}
I feel sometimes that I'm reinventing the wheel.
I'm wondering if there are any utility methods in java/jakarta commons/guava/?, that will go deeper in the collection and do something (test, modify, remove) with the elements.
I wrote this method and now I feel that there is some one-liner that can do it.
/**
* Find index of first line that contains search string.
*/
public static int findIdx(List<String> list, String search) {
for (int i = 0, n = list.size(); i < n; i++)
if (list.get(i).contains(search))
return i;
return -1;
}
Guava has Iterables.indexOf with a predicate:
int index = Iterables.indexOf(list, new Predicate<String> {
#Override public boolean apply(String input) {
return input.contains(search);
}
});
Not much better, admittedly - and you need to make search final. But at least with Java 8 you'll be able to write something like:
int index = Iterables.indexOf(list, input => input.contains(search));
(Or at least something like that. And possibly in an extension method syntax...)
Guava has what you want in Iterables.indexOf(), although I wouldn't exactly argue that it'll make your code more readable:
public static int findIdx(List<String> list, final String search) {
return Iterables.<String> indexOf(list, new Predicate<String>() {
public boolean apply(String s) {
return s.contains(search);
}
});
}