Suffix array & Binary Search - java

I have been following a tutorial I found. It is however in C++ and I'm using Java so there might have been a few things lost in translation. I've tried both googling and searching here and while there seem to be plenty of asked questions I still remain stuck. Though it feels like I'm very close.
According to the tutorial, there should be a match for the pattern 'nan' but there simply is no match when I'm running it. What am I missing? Sorry for code that unformated itself when pasted.
package u1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Arrays;
import java.util.Scanner;
public class SuffixSort {
public Element[] processPattern(String pattern) {
Element[] patternArray = new Element[pattern.length()];
for (int i = 0; i < pattern.length(); i++) {
patternArray[i] = new Element(i, pattern.substring(i, pattern.length()));
}
Arrays.sort(patternArray);
return patternArray;
}
public void binarySearch(String text, String pattern, Element[] array) {
int left = 0, right = text.length() - 1;
int mid = 0, result;
while (left <= right) {
mid = left + (right - left) / 2;
result = pattern.compareTo(array[mid].getSuffix());
if (result == 0) {
System.out.println("Match: " + array[mid].getIndex());
return;
} else if (result < 0) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
public static void main(String[] args) {
try {
String text = "banana";
String pattern = "nan";
SuffixSort ss = new SuffixSort();
Scanner in = new Scanner(new FileReader("src/resources/100k.txt"));
/*
* while (in.hasNextLine()) { text += in.nextLine(); }
*/
Element[] suffixArray = ss.processPattern(text);
double runtime = System.nanoTime();
ss.binarySearch(text, pattern, suffixArray);
runtime = (System.nanoTime() - runtime) / 1000000;
in.close();
System.out.println(runtime);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Other class
package u1;
public class Element implements Comparable<Element>{
private int index;
private String suffix;
public Element(int index, String suffix){
this.index = index;
this.suffix = suffix;
}
#Override
public int compareTo(Element o) {
return this.getSuffix().compareTo(o.getSuffix());
}
public int getIndex() {
return index;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}

Related

Why saving the char '�' to a file saves it as '?'?

I learned about Huffman Coding and tried to apply. So I made a very basic text reader that can only open and save files. And wrote a decorator that can be used to compress the text before saving (which uses Huffman Coding).
There was a bug that I couldn't find and after alot of debugging I figured out that when I compress the text, as a result the character � may be in the compressed text. For example, the text ',-.:BCINSabcdefghiklmnoprstuvwy gets compressed to 앐낧淧翵�ဌ䤺큕㈀.
I figured out that the bug lies in the saving function. When I save the compressed text, it changes every occurence of � to ?. For example, when saving 앐낧淧翵�ဌ䤺큕㈀, I get 앐낧淧翵?ဌ䤺큕㈀.
When I try to read the saved file to decompress it, I get a different string so the decompression fails.
What makes it more difficult is that the saving function alone works fine, but it doesn't work when using it in my code. the function looks like this:
public void save() throws IOException {
FileWriter fileWriter = new FileWriter(this.filename);
fileWriter.write(this.text);
fileWriter.close();
}
It's confusing that this.text at the moment of saving is 앐낧淧翵�ဌ䤺큕㈀ yet it saves it as 앐낧淧翵?ဌ䤺큕㈀.
As I said before, the function works fine when alone, but doesn't work in my code. I couldn't do any thing more that removing as much as possible from my code and and putting it here. Anyways, a breakpoint can be put at the function FileEditor::save and you'll find that this.text at the moment of saving is 앐낧淧翵�ဌ䤺큕㈀ and the content of the file is 앐낧淧翵?ဌ䤺큕㈀.
Code:
FileEditor is right below Main.
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.PriorityQueue;
import java.util.TreeMap;
import static pack.BitsManipulator.CHAR_SIZE_IN_BITS;
public class Main {
public static void main(String[] args) throws IOException {
String text = " ',-.:BCINSabcdefghiklmnoprstuvwy";
FileEditor fileEditor2 = new FileEditor("file.txt");
HuffmanDecorator compressor = new HuffmanDecorator(fileEditor2);
compressor.setText(text);
System.out.println(compressor.getText());
compressor.save();
}
}
class FileEditor implements BasicFileEditor {
private String filename;
private String text;
public FileEditor(String filename) throws IOException {
this.filename = filename;
File file = new File(filename);
StringBuilder builder = new StringBuilder();
if (!file.createNewFile()) {
FileReader reader = new FileReader(file);
int ch;
while ((ch = reader.read()) != -1)
builder.append((char) ch);
}
this.text = builder.toString();
}
#Override
public String getText() {
return text;
}
#Override
public void setText(String text) {
this.text = text;
}
#Override
public void save() throws IOException {
FileWriter fileWriter = new FileWriter(this.filename);
fileWriter.write(this.text);
fileWriter.close();
}
}
interface BasicFileEditor {
String getText();
void setText(String text);
void save() throws IOException;
}
abstract class FileEditorDecorator implements BasicFileEditor {
FileEditor fileEditor;
public FileEditorDecorator(FileEditor fileEditor) {
this.fileEditor = fileEditor;
}
#Override
public String getText() {
return fileEditor.getText();
}
#Override
public void setText(String text) {
fileEditor.setText(text);
}
#Override
public void save() throws IOException {
String oldText = getText();
setText(getModifiedText());
fileEditor.save();
setText(oldText);
}
protected abstract String getModifiedText();
}
class HuffmanDecorator extends FileEditorDecorator {
public HuffmanDecorator(FileEditor fileEditor) {
super(fileEditor);
}
#Override
protected String getModifiedText() {
HuffmanCodingCompressor compressor = new HuffmanCodingCompressor(getText());
return compressor.getCompressedText();
}
}
class HuffmanCodingCompressor {
String text;
public HuffmanCodingCompressor(String text) {
this.text = text;
}
public String getCompressedText() {
EncodingBuilder builder = new EncodingBuilder(text);
return builder.getCompressedText();
}
}
class Node implements Comparable<Node> {
public Node left;
public Node right;
public int value;
public Character character;
public Node(Node left, Node right, int value) {
this(left, right, value, null);
}
public Node(Node left, Node right, int value, Character character) {
this.left = left;
this.right = right;
this.character = character;
this.value = value;
}
#Override
public int compareTo(Node o) {
return this.value - o.value;
}
public boolean isLeafNode() {
return left == null && right == null;
}
Node getLeft() {
if (left == null)
left = new Node(null, null, 0);
return left;
}
Node getRight() {
if (right == null)
right = new Node(null, null, 0);
return right;
}
}
class EncodingBuilder {
private String text;
private Node encodingTree;
private TreeMap<Character, String> encodingTable;
public EncodingBuilder(String text) {
this.text = text;
buildEncodingTree();
buildEncodingTableFromTree(encodingTree);
}
private void buildEncodingTableFromTree(Node encodingTree) {
encodingTable = new TreeMap<>();
buildEncodingTableFromTreeHelper(encodingTree, new StringBuilder());
}
public void buildEncodingTableFromTreeHelper(Node root, StringBuilder key) {
if (root == null)
return;
if (root.isLeafNode()) {
encodingTable.put(root.character, key.toString());
} else {
key.append('0');
buildEncodingTableFromTreeHelper(root.left, key);
key.deleteCharAt(key.length() - 1);
key.append('1');
buildEncodingTableFromTreeHelper(root.right, key);
key.deleteCharAt(key.length() - 1);
}
}
public void buildEncodingTree() {
TreeMap<Character, Integer> freqArray = new TreeMap<>();
for (int i = 0; i < text.length(); i++) {
// improve here.
char c = text.charAt(i);
if (freqArray.containsKey(c)) {
Integer freq = freqArray.get(c) + 1;
freqArray.put(c, freq);
} else {
freqArray.put(c, 1);
}
}
PriorityQueue<Node> queue = new PriorityQueue<>();
for (Character c : freqArray.keySet())
queue.add(new Node(null, null, freqArray.get(c), c));
if (queue.size() == 1)
queue.add(new Node(null, null, 0, '\0'));
while (queue.size() > 1) {
Node n1 = queue.poll();
Node n2 = queue.poll();
queue.add(new Node(n1, n2, n1.value + n2.value));
}
encodingTree = queue.poll();
}
public String getCompressedTextInBits() {
StringBuilder bits = new StringBuilder();
for (int i = 0; i < text.length(); i++)
bits.append(encodingTable.get(text.charAt(i)));
return bits.toString();
}
public String getCompressedText() {
String compressedInBits = getCompressedTextInBits();
int remainder = compressedInBits.length() % CHAR_SIZE_IN_BITS;
int paddingNeededToBeDivisibleByCharSize = CHAR_SIZE_IN_BITS - remainder;
String compressed = BitsManipulator.convertBitsToText(compressedInBits + "0".repeat(paddingNeededToBeDivisibleByCharSize));
return compressed;
}
}
class BitsManipulator {
public static final int CHAR_SIZE_IN_BITS = 16;
public static int bitsInStringToInt(String bits) {
int result = 0;
for (int i = 0; i < bits.length(); i++) {
result *= 2;
result += bits.charAt(i) - '0';
}
return result;
}
public static String convertBitsToText(String bits) {
if (bits.length() % CHAR_SIZE_IN_BITS != 0)
throw new NumberOfBitsNotDivisibleBySizeOfCharException();
StringBuilder result = new StringBuilder();
for (int i = 0; i < bits.length(); i += CHAR_SIZE_IN_BITS)
result.append(asciiInBitsToChar(bits.substring(i, i + CHAR_SIZE_IN_BITS)));
return result.toString();
}
public static char asciiInBitsToChar(String bits) {
return (char) bitsInStringToInt(bits);
}
public static class NumberOfBitsNotDivisibleBySizeOfCharException extends RuntimeException {
}
}
� is the Unicode replacement character U+FFFD. If you encode that in a non-unicode encoding, it will get converted to a regular question mark, as non-unicode encodings can't encode all unicode characters, and this provides a "safety" (i.e. convert everything to question marks that we can't encode).
You seem to be confused about the difference between binary data and text data, leading you to look at compressed data as if it were Korean text instead of binary data. You need to store (and observe) the data as bytes, not chars or Strings.

Comparing words

I have problem with my code. I wrote program for count words in text, but I have small problem with patterns which must be search in text. Maybe somebody can help me.
import java.util.*;
class KomparatorLicz implements Comparator<Word> {
#Override
public int compare(Word arg0, Word arg1) {
return arg1.amount - arg0.amount;
}
}
class KomparatorString implements Comparator<Word> {
#Override
public int compare(Word obj1, Word obj2) {
if (obj1.content == obj2.content) {
return 0;
}
if (obj1.content == null) {
return -1;
}
if (obj2.content == null) {
return 1;
}
return obj1.content.compareTo(obj2.content);
}
}
class Word
{
public String content;
public int amount;
public Word(String content, int amount) {
this.content = content;
this.amount = amount;
}
#Override
public String toString() {
return "Word [content=" + content + ", amount=" + amount + "]";
}
}
public class Source4 {
public static float procent(int wordCount, int oneWord)
{
return (((float)oneWord*100)/(float)wordCount);
}
public static void main(String[] args) {
String line, wordsLine[];
String klucze = null;
int valTemp;
int wordCount=0;
int keyWords=0;
HashMap<String, Word> slownik = new HashMap<String, Word>();
ArrayList<Word> lista= new ArrayList<Word>();
ArrayList<Object> keyWordsList = new ArrayList<Object>();
Scanner in = new Scanner(System.in);
String alph = in.nextLine();
keyWords = in.nextInt();
for(int i=0; i<keyWords; i++)
{
klucze = in.next();
keyWordsList.add(klucze);
}
while(in.hasNextLine())
{
line = in.nextLine();
if(line.equals("koniec")) break;
wordsLine = line.split("[^" + alph + "]");
for(String s : wordsLine) {
if(s != null && s.length() > 0)
{
wordCount++;
if(slownik.containsKey(s))
{
valTemp = slownik.get(s).amount;
slownik.remove(s);
valTemp++;
slownik.put(s, new Word(s,valTemp));
}
else
{
slownik.put(s, new Word(s,1));
}
}
}
}
for (String key : slownik.keySet())
{
lista.add(slownik.get(key));
}
Collections.sort(lista, new KomparatorString());
StringBuffer result = new StringBuffer();
int keyWordCounter=0;
int amountBuff=0;
float percentBuff=0;
for (int i = 0; i<lista.size();i++)
{
if(keyWordsList.contains(lista.get(i)))
{
result.append(amountBuff+" "+percentBuff+"%");
amountBuff = 0;
percentBuff = 0;
result.append("\n");
result.append(lista.get(i).amount+" "+(procent(wordCount,lista.get(i).amount)+"%"));
result.append(" "+lista.get(i).content);
result.append("\n");
keyWordCounter+=lista.get(i).amount;
}
else
{
amountBuff+=lista.get(i).amount;
percentBuff+=procent(wordCount,lista.get(i).amount);
}
}
result.append(amountBuff+" "+percentBuff+"%");
System.out.println("Wersja AK");
System.out.println(keyWords+" różnych słów kluczowych");
System.out.println(wordCount+" wystąpień wszystkich słów");
System.out.println(keyWordCounter+" "+procent(wordCount,keyWordCounter)+"% "+" wystąpień słów kluczowych");
System.out.println((wordCount-keyWordCounter)+" "+procent(wordCount,(wordCount-keyWordCounter))+"% wystąpień innych słów");
System.out.println(result);
}
}
It's wrong code if(keyWordsList.contains(lista.get(i))).
You need if(keyWordsList.contains(lista.get(i).content)).

Stack Overflow error adding an object in ArrayList of []

I get stack overflow error when I try to load(). I am trying to read PhoneBookEntry objects from a txt file. The txt file has a name and number which make up the PhoneBookEntry object.
Can you please let me know what I'm doing wrong?
package HashSet;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Scanner;
public class PhoneBook {
int capacity = 10;
private ArrayList<PhoneBookEntry>[] buckets;
public PhoneBook() {
this(10);
}
public PhoneBook(int size) {
capacity = size;
buckets = new ArrayList[size];
for (int i = 0; i < buckets.length; i++) {
buckets[i] = new ArrayList<PhoneBookEntry>();
}
}
public int getSize() {
int tot = 0;
for (ArrayList<PhoneBookEntry> x : buckets)
tot += x.size();
return tot;
}
public boolean add(PhoneBookEntry entry) {
if (contains(entry))
return false;
int x = Math.abs(entry.hashCode());
buckets[x % buckets.length].add(entry);
return true;
}
public void load()
{
InputStream is = getClass().getClassLoader().getResourceAsStream("phone.txt");
Scanner scan = new Scanner(is);
if (scan.hasNext())
add(new PhoneBookEntry(scan.next());
}
public void bucketSize() {
for (int i = 0; i < buckets.length; i++)
System.out.println(i + " " + buckets[i].size());
}
public boolean contains(PhoneBookEntry word) {
int x = Math.abs(word.hashCode());
return buckets[x % buckets.length].contains(word);
}
public int getCapacity() {
return capacity;
}
public static void main(String[] args) {
PhoneBook phone = new PhoneBook();
phone.load();
}
}
package HashSet;
import java.util.LinkedList;
import java.util.ListIterator;
public class PhoneBookEntry {
String n;
Integer nr;
LinkedList<PhoneBookEntry> list;
public PhoneBookEntry(String name, int number) {
list = new LinkedList<PhoneBookEntry>();
n = name;
nr = number;
list.add(new PhoneBookEntry(n, nr));
}
public String getN() {
return n;
}
public void setN(String n) {
this.n = n;
}
public Integer getNr() {
return nr;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((n == null) ? 0 : n.hashCode());
result = prime * result + ((nr == null) ? 0 : nr.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PhoneBookEntry other = (PhoneBookEntry) obj;
if (n == null) {
if (other.n != null)
return false;
} else if (!n.equals(other.n))
return false;
if (nr == null) {
if (other.nr != null)
return false;
} else if (!nr.equals(other.nr))
return false;
return true;
}
public void setNr(Integer nr) {
this.nr = nr;
}
#Override
public String toString() {
return n + " " + nr;
}
}
Every new phone book entry creates a new phone book entry that creates a new phone book entry that creates a new phome book entry, etc... ad infinitum. That is, until the stack space runs out.
You need to rethink your application data structure.
public PhoneBookEntry(String name, int number) {
list = new LinkedList<PhoneBookEntry>();
n = name;
nr = number;
list.add(new PhoneBookEntry(n, nr));
}
is causing an infinite recursion. You likely need a new class to put in the linked list (PhoneNumber or some such if a PhoneBookEntry can contain multiple names/numbers, otherwise ditch it.)

Guava: Splitter and considering Escaping?

I am interested in the Splitting possibility of Guava:
Splitter.on("|").split("foo|bar|baz");
// => "foo", "bar", "baz"
This works correctly.
What now if I want to split on "|" but not between "[" and "]":
Splitter.on(something).split("foo|ba[r|ba]z");
// => "foo", "ba[r|ba]z"
From what I understood, it is not possible to define this "something" in Guava.
I found this:
Issue 799: Add google escape library to Guava. Is this related ?
The proper way to deal with this is to make a parser. It's really easy nowadays, just use a parser combinator, such as JParsec. You'll get something like this:
class ParserFactory {
Parser escapedSequence() {
return Parsers.between(Scanners.string("["),
Scanners.anyCharacterButNot("]"), Scanners.string("]"));
}
Parser chunk() {
return Parsers.or(escapedSequence(), Scanners.anyCharacterButNot("|"));
}
Parsers wholeThing() {
return Parsers.separatedBy(chunk().plus(), Scanners.string("|"));
}
}
Here's the code which works for given use case (Used existing Splitter code as a reference)
public class Splitter {
private final CharMatcher trimmer;
private final CharMatcher startTextQualifier;
private final CharMatcher endTextQualifier;
private final Strategy strategy;
private Splitter(Strategy strategy, CharMatcher trimmer, CharMatcher startTextQualifier, CharMatcher endTextQualifier) {
this.strategy = strategy;
this.trimmer = trimmer;
this.startTextQualifier = startTextQualifier;
this.endTextQualifier = endTextQualifier;
}
private Splitter(Strategy strategy) {
this(strategy, CharMatcher.NONE, CharMatcher.NONE, CharMatcher.NONE);
}
public Splitter trimResults(CharMatcher trimmer) {
checkNotNull(trimmer);
return new Splitter(strategy, trimmer, startTextQualifier, endTextQualifier);
}
public Splitter ignoreIn(CharMatcher startTextQualifier, CharMatcher endTextQualifier) {
checkNotNull(startTextQualifier);
checkNotNull(endTextQualifier);
return new Splitter(strategy, trimmer, startTextQualifier, endTextQualifier);
}
public Splitter ignoreIn(char startTextQualifier, char endTextQualifier) {
return ignoreIn(CharMatcher.is(startTextQualifier), CharMatcher.is(endTextQualifier));
}
public Splitter trimResults() {
return trimResults(CharMatcher.WHITESPACE);
}
public static Splitter on(final CharMatcher separatorMatcher) {
checkNotNull(separatorMatcher);
return new Splitter(new Strategy() {
#Override public SplittingIterator iterator(Splitter splitter, final CharSequence toSplit) {
return new SplittingIterator(splitter, toSplit) {
#Override int separatorStart(int start) {
boolean wrapped = false;
for (int i = start; i < toSplit.length(); i++) {
/**
* Suppose start text qualifier = '[' and end text qualifier = ']' then following code
* doesn't address cases for multiple start-end combinations i.e it doesn't see whether
* end is properly closed e.g. for configuration like - {#code
* Splitter.on("|")..ignoreIn('[', ']').split("abc|[abc|[def]ghi]|jkl")
* results -> abc, [abc|[def]ghi], jkl
}
*/
if (!wrapped && startTextQualifier.matches(toSplit.charAt(i))) {
wrapped = true;
} else if (wrapped && endTextQualifier.matches(toSplit.charAt(i))) {
wrapped = false;
}
if (!wrapped && separatorMatcher.matches(toSplit.charAt(i))) {
return i;
}
}
return -1;
}
#Override int separatorEnd(int separatorPosition) {
return separatorPosition + 1;
}
};
}
});
}
public static Splitter on(final String separator) {
checkArgument(!separator.isEmpty(), "The separator may not be the empty string.");
checkArgument(separator.length() <= 2, "The separator's max length is 2, passed - %s.", separator);
if (separator.length() == 1) {
return on(separator.charAt(0));
}
return new Splitter(new Strategy() {
#Override public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {
return new SplittingIterator(splitter, toSplit) {
#Override public int separatorStart(int start) {
int delimiterLength = separator.length();
boolean wrapped = false;
positions:
for (int p = start, last = toSplit.length() - delimiterLength; p <= last; p++) {
for (int i = 0; i < delimiterLength; i++) {
if (startTextQualifier.matches(toSplit.charAt(i))) {
wrapped = !wrapped;
}
if (!wrapped && toSplit.charAt(i + p) != separator.charAt(i)) {
continue positions;
}
}
return p;
}
return -1;
}
#Override public int separatorEnd(int separatorPosition) {
return separatorPosition + separator.length();
}
};
}
});
}
public static Splitter on(char separator) {
return on(CharMatcher.is(separator));
}
public Iterable<String> split(final CharSequence sequence) {
checkNotNull(sequence);
return new Iterable<String>() {
#Override public Iterator<String> iterator() {
return spliterator(sequence);
}
};
}
private Iterator<String> spliterator(CharSequence sequence) {
return strategy.iterator(this, sequence);
}
private interface Strategy {
Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
}
private abstract static class SplittingIterator extends AbstractIterator<String> {
final CharSequence toSplit;
final CharMatcher trimmer;
final CharMatcher startTextQualifier;
final CharMatcher endTextQualifier;
/**
* Returns the first index in {#code toSplit} at or after {#code start}
* that contains the separator.
*/
abstract int separatorStart(int start);
/**
* Returns the first index in {#code toSplit} after {#code
* separatorPosition} that does not contain a separator. This method is only
* invoked after a call to {#code separatorStart}.
*/
abstract int separatorEnd(int separatorPosition);
int offset = 0;
protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
this.trimmer = splitter.trimmer;
this.startTextQualifier = splitter.startTextQualifier;
this.endTextQualifier = splitter.endTextQualifier;
this.toSplit = toSplit;
}
#Override
protected String computeNext() {
if (offset != -1) {
int start = offset;
int separatorPosition = separatorStart(offset);
int end = calculateEnd(separatorPosition);
start = trimStartIfRequired(start, end);
end = trimEndIfRequired(start, end);
if (start != end)
return toSplit.subSequence(start, end).toString();
}
return endOfData();
}
private int calculateEnd(int separatorPosition) {
int end;
if (separatorPosition == -1) {
end = toSplit.length();
offset = -1;
} else {
end = separatorPosition;
offset = separatorEnd(separatorPosition);
}
return end;
}
private int trimEndIfRequired(int start, int end) {
while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
end--;
}
return end;
}
private int trimStartIfRequired(int start, int end) {
while (start < end && trimmer.matches(toSplit.charAt(start))) {
start++;
}
return start;
}
}
}
Small test -
public static void main(String[] args) {
Splitter splitter = Splitter.on("|").ignoreIn('[', ']');
System.out.println(Joiner.on(',').join(splitter.split("foo|ba[r|ba]z")));
// yields -> foo,ba[r|ba]z
}
Please note - this code isn't tested and does not address all the cases, feel free to modify as per your need.
Guava splitter is very powerful, it can handle regex separators, it can split into maps and more. But what you are trying to achieve is really out of scope of any generic parser.
You want a splitter with on/off switch. I believe the only way to do it is manually, something like this:
List<String> ls=new ArrayList<String>();
int b=0;
int j=0;
String str="foo|ba[r|ba]z";
int e=str.indexOf('|');
do{
if(b>j)
{
j=str.indexOf('[',j);
while(j>0 && e>=j){
j=str.indexOf(']',j);
if (j<0){
ls.add(str.substring(b));
return ;
}
j=str.indexOf('[',j);
}
}
ls.add(str.substring(b,e));
System.out.println(str.substring(b,e));
b=++e;
e=str.indexOf('|',e);
} while( e >= 0);
(Disclaimer: this code is just for giving an idea, it is not working)

Generic Class Iterator

I have three classes, those being Lister, ObjectSortedList and SortedListProgram. I'm having trouble with the iterator for the generic class. What am I doing wrong?
This is the error I get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
at objectsortedlist.ObjectSortedList.getData(ObjectSortedList.java:122)
at objectsortedlist.Lister.hasNext(Lister.java:28)
at objectsortedlist.SortedListProgram.main(SortedListProgram.java:52)
Java Result: 1
Here are my classes:
package objectsortedlist;
import java.util.Iterator;
/**
*
* #author Steven
*/
public class ObjectSortedList<T> implements Cloneable, Iterable<T> {
private T[] data;
private int capacity;
public ObjectSortedList()
{
final int init_capacity = 10;
capacity = 0;
data = (T[])new Object[init_capacity];
}
public ObjectSortedList(int init_capacity)
{
if(init_capacity < 0)
throw new IllegalArgumentException("Initial capacity is negative: " + init_capacity);
capacity = 0;
data = (T[])new Object[init_capacity];
}
private boolean empty()
{
if(data.length == 0 || data[0] == null)
return true;
else
return false;
}
public int length()
{
return capacity;
}
public void insert(T element)
{
if(capacity == data.length)
{
ensureCapacity(capacity * 2 + 1);
}
data[capacity] = element;
capacity++;
}
public boolean delete(T target)
{
int index;
if(target == null)
{
index = 0;
while((index < capacity) && (data[index] != null))
index++;
}
else
{
index = 0;
while((index < capacity) && (!target.equals(data[index])))
index++;
}
if(index == capacity)
return false;
else
{
capacity--;
data[index] = data[capacity];
data[capacity] = null;
return true;
}
}
private void ensureCapacity(int minCapacity)
{
T[] placeholder;
if(data.length < minCapacity)
{
placeholder = (T[])new Object[minCapacity];
System.arraycopy(data, 0, placeholder, 0, capacity);
data = placeholder;
}
}
public ObjectSortedList<T> clone()
{
// Cloning
ObjectSortedList<T> answer;
try
{
answer = (ObjectSortedList<T>) super.clone();
}
catch(CloneNotSupportedException cnse)
{
throw new RuntimeException("This class does not implement cloneable.");
}
answer.data = data.clone();
return answer;
}
#Override
public Iterator<T> iterator()
{
return (Iterator<T>) new Lister<T>(this, 0);
}
public T getData(int index)
{
return (T)data[index];
}
}
package objectsortedlist;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
*
* #author Steven
*/
public class Lister<T> implements Iterator<T>
{
private ObjectSortedList<T> current;
private int index;
public Lister(ObjectSortedList<T> top, int index)
{
current = top;
this.index = index;
}
#Override
public boolean hasNext()
{
return (current.getData(index) == null);
}
#Override
public T next()
{
T answer;
if(!hasNext())
throw new NoSuchElementException("The Lister is empty.");
answer = current.getData(index+1);
return answer;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Don't use this. Use objectsortedlist.SortedList.delete(T target).");
}
}
package objectsortedlist;
import java.util.Scanner;
/**
*
* #author Steven
*/
public class SortedListProgram {
private static Scanner scan = new Scanner(System.in);
private static String[] phraseArray = {"Hullabaloo!", "Jiggery pokery!", "Fantastic!", "Brilliant!", "Clever!", "Geronimo!", "Fish sticks and custard.", "Spoilers!",
"Exterminate!", "Delete!", "Wibbly-wobbly!", "Timey-wimey!"};
private static Lister<String> print;
public static void main(String args[])
{
int phraseNo = 0;
System.out.println("I'm gonna say some things at you, and you're going to like it."
+ " How many things would you like me to say to you? Put in an integer from 1-12, please.");
try
{
phraseNo = Integer.parseInt(scan.nextLine());
while((phraseNo < 1) || (phraseNo > 12))
{
System.out.println("The integer you entered wasn't between 1 and 12. Make it in between those numbers. Please? Pleaseeeee?");
phraseNo = Integer.parseInt(scan.nextLine());
}
}
catch(NumberFormatException nfe)
{
System.out.println("C'mon, why don't you follow directions?");
phraseNo = 0;
}
if(phraseNo == 0);
else
{
ObjectSortedList<String> phrases = new ObjectSortedList<String>(phraseNo);
for(int i = 0; i < phrases.length(); i++)
{
phrases.insert(phraseArray[i]);
}
print = new Lister<String>(phrases, phraseNo);
while(print.hasNext())
System.out.println(print.next());
}
}
}
After looking at your code I found multiple issues, here are they:
In your SortedListProgram class, in following code the phrases.length() will be 0, so the it will never go in that loop.
ObjectSortedList<String> phrases = new ObjectSortedList<String>(phraseNo);
for(int i = 0; i < phrases.length(); i++)
{
phrases.insert(phraseArray[i]);
}
Moreover in SortedListProgram class's this call sequence
print.hasNext() -> current.getData(index)
the index passed is equal to size of data array field in the
ObjectSortedList class and Since in java array indexes ranges from
zero to array size -1. So you are bound to get
java.lang.ArrayIndexOutOfBoundsException always.
Please correct your code.

Categories

Resources