LifeQuestioner LifeQuestioner - 5 months ago 8
Java Question

Efficient way of returning next N words & previous N words to display

I wish to allow the user to view a string, N words at a time. They can move both forwards and backwards, such that backwards will display the previous N words. Also, as we are limited by screen space, so I want to select only the words that will fit, up to n (whole words, no ...).

So, I created the initial not too pretty method:

import java.util.ArrayList;

public class Test {

static String text = "This is a dummny sentence. I am a dummy sentence two. This is dummy sentence 3. This is a dummy sentence";

static int currentWordIndex = 0;

public static void main(String[] args) {

String nextWords = getNextWords(5, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);

nextWords = getNextWords(3, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);

nextWords = getNextWords(3, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);

nextWords = getNextWords(3, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);


String prevWords = getPreviousWords(3, 30);
System.out.println("Previous Sentence: " + prevWords);
System.out.println("Index: " + currentWordIndex);

prevWords = getPreviousWords(3, 30);
System.out.println("PreviousSentence: " + prevWords);
System.out.println("Index: " + currentWordIndex);

prevWords = getPreviousWords(3, 30);
System.out.println("PreviousSentence: " + prevWords);
System.out.println("Index: " + currentWordIndex);

nextWords = getNextWords(3, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);

nextWords = getNextWords(3, 30);
System.out.println("Sentence: " + nextWords);
System.out.println("Index: " + currentWordIndex);


}

public static String getPreviousWords(int n, int maxCharacterLength) {
ArrayList<String> initialSelection = new ArrayList();
String[] splitWords = text.split(" ");
int charCount = 0;
int maxN = currentWordIndex - n;
if(maxN < 0) {
maxN = 0;
}
for (int i = maxN; i < currentWordIndex; i++) {
if(i > splitWords.length) {
break;
}
initialSelection.add(splitWords[i]);
charCount += splitWords[i].length();
}

if (charCount > maxCharacterLength) {
charCount = 0;
for (int x = 0; x < initialSelection.size(); x++) {
if (initialSelection.size() == 0)
return null;
initialSelection.remove(initialSelection.size() - 1);
for (String s : initialSelection) {
charCount += s.length();
}
if (charCount <= maxCharacterLength) {
break;
}
}
}
StringBuilder sb = new StringBuilder();
for (String s : initialSelection) {
sb.append(s + " ");
}
if(currentWordIndex - initialSelection.size() < 0) {
currentWordIndex = 0;
} else {
currentWordIndex -= initialSelection.size();
}
return sb.toString().substring(0, sb.length());
}

/**
* Obtains the next n number of words given the maximum number of characters that can fit on the screen.
* If not all words fit on the screen
*
* @param n number of words
* @param maxCharacterLength of text that can fit on the screen.
* @return next words
*/
public static String getNextWords(int n, int maxCharacterLength) {
ArrayList<String> initialSelection = new ArrayList();
int charCount = 0;
String[] splitWords = text.split(" ");
int maxN = currentWordIndex + n;
if (maxN > splitWords.length - 1) {
maxN = splitWords.length - 1;
}
// add the words
for (int i = currentWordIndex; i < maxN; i++) {
if (i > splitWords.length - 1)
break;
initialSelection.add(splitWords[i]);
charCount += splitWords[i].length();
}

// if there's too many, remove the last word until everything fits
if (charCount > maxCharacterLength) {
charCount = 0;
for (int x = 0; x < initialSelection.size(); x++) {
if (initialSelection.size() == 0)
return null;
initialSelection.remove(initialSelection.size() - 1);
for (String s : initialSelection) {
charCount += s.length();
}
if (charCount <= maxCharacterLength) {
break;
}
}
}

// add back into a string
StringBuilder sb = new StringBuilder();
for (String s : initialSelection) {
sb.append(s + " ");
}

// update the index/pivot based on the words selected
if (currentWordIndex + initialSelection.size() < splitWords.length - 1) {
currentWordIndex += initialSelection.size();
} else {
currentWordIndex = splitWords.length;
}
return sb.toString().substring(0, sb.length());
}

}


Which gives this output:

Next Sentence: One two three four five.
Index: 5
Next Sentence: Six Seven Either,
Index: 8
Next Sentence: Nine, Ten, Eleven.
Index: 11
Next Sentence: Twelve thirdteen fourteen
Index: 14
Previous Sentence: Twelve thirdteen fourteen
Index: 11
PreviousSentence: Nine, Ten, Eleven.
Index: 8
PreviousSentence: Six Seven Either,
Next Index: 5
Next Sentence: Six Seven Either,
Index: 8
Next Sentence: Nine, Ten, Eleven.
Index: 11


Which is incorrect. It appears the next and previous is working - just not when changing between them. It should say:

Next Sentence: One two three four five.
Index: 5
Next Sentence: Six Seven Either,
Index: 8
Next Sentence: Nine, Ten, Eleven.
Index: 11
Next Sentence: Twelve thirdteen fourteen
Index: 14
Previous Sentence: Nine, Ten, Eleven.
Index: 11
PreviousSentence: Six, Seven, Either.
Index: 8
PreviousSentence: three four five,
Index: 5
Next Sentence: Six Seven Either,
Index: 8
Next Sentence: Nine, Ten, Eleven.
Index: 11


I understand what the problem is: after the getNext" increments, it sets the marker at the begining of the next sentence. Thus when 'getPrevious" is called, it calls, the last sentence (the current one already on display).

So I suppose the solution would be to have both a beginning and end marker - marking the start and end of the sentence indexs.

But i'm wondering if anyone has a more elegant solution so solving this issue?

Answer

Try this

 public class Test {

    static String text = "one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen";

    static int currentWordIndex = 0;
    private static List<String> list = new LinkedList<String>();

    public void createTokens() {
        String[] splitWords = text.split(" ");
        for (int i = 0; i < splitWords.length; i++) {
            list.add(splitWords[i]);
        }
    }

    public String getPreviousWords(int n, int maxCharacterLength) {
        StringBuilder strBuilder = new StringBuilder();
        int characterCount = 0;
        int item_size = 0;
        // you need to check this negative or not
        currentWordIndex = currentWordIndex - n; 
        ListIterator<String> nextIter = list.listIterator(currentWordIndex);
        while (nextIter.hasPrevious() && item_size < n) {
            String elem = (String) nextIter.previous();
            characterCount += elem.length();
            if (characterCount > maxCharacterLength) {
                break;
            }
            strBuilder.append(elem);
            strBuilder.append(" ");
            item_size++;
        }

        return strBuilder.toString();
    }

    /**
     * Obtains the next n number of words given the maximum number of characters
     * that can fit on the screen. If not all words fit on the screen
     *
     * @param n
     *            number of words
     * @param maxCharacterLength
     *            of text that can fit on the screen.
     * @return next words
     */
    public String getNextWords(int n, int maxCharacterLength) {
        StringBuilder strBuilder = new StringBuilder();
        int characterCount = 0;
        int item_size = 0;
        ListIterator<String> nextIter = list.listIterator(currentWordIndex);
        while (nextIter.hasNext() && item_size < n) {
            String elem = (String) nextIter.next();
            characterCount += elem.length();
            if (characterCount > maxCharacterLength) {
                break;
            }
            strBuilder.append(elem);
            strBuilder.append(" ");
            item_size++;
        }
        return strBuilder.toString();

    }

}

App.java

    public class App {

    public static void main(String[] args) {
            Test t = new Test();
            t.createTokens();
            String nextWords = t.getNextWords(5, 30);
            System.out.println("Sentence: " + nextWords);
            String nextWords2 = t.getNextWords(5, 30);
            System.out.println("Sentence: " + nextWords2);
            String nextWords3 = t.getNextWords(5, 30);
            System.out.println("Sentence: " + nextWords3);

            String previousWords = t.getPreviousWords(5, 30);
            System.out.println("Sentence: " + previousWords);
    }
}

Output:

Sentence: one two three four five
Sentence: six seven eight nine ten 
Sentence: eleven twelve thirteen fourteen 
Sentence: ten nine eight seven six