Array of strings to a formatted string - java

I've tried to create a method that takes in an array of strings and returns a single formatted string.
The last word should be separated by the word 'and' instead of a comma.
But it doesn't work as expected :)
It doesn't replace the last comma by the word "and".
Can you please advise where is my mistake.
thanks.
public class Kata {
public static String formatWords(String[] words) {
List<String> words1 = Arrays.asList(words);
ListIterator<String> wordIter = words1.listIterator();
StringBuilder out = new StringBuilder();
while (wordIter.hasNext()) {
out.append(wordIter.next());
if (wordIter.hasNext()) {
out.append(",");
}
}
return out.toString().replaceAll(",$", "and");
}
}

Since you may have empty items, first use a list to clear the empty items:
public static String formatWords(String[] words) {
if (words == null)
return "";
List<String> list = new ArrayList<>();
for (String word : words) {
word = word.trim();
if (!word.isEmpty())
list.add(word);
}
StringBuilder out = new StringBuilder();
int len = list.size();
for (int i = 0; i < len; i++) {
out.append(list.get(i));
if (i == len - 2)
out.append(" and ");
else if (i < len - 2)
out.append(",");
}
return out.toString();
}
public static void main(String[] args) {
String[] array = {"", "apples", "", "oranges", "", "melons", ""};
System.out.println(formatWords(array));
}
will print:
apples,oranges and melons

I'd iterate up to the before-last element and concat the strings with commas, and then concat the last one with an "and":
public static String formatWords(String[] words) {
// Handle nulls and empty arrays
if (words == null || words.length) {
return "";
}
// Handle the first word
StringBuilder sb = new StringBuilder(words[0]);
// Handle all the words from the second to the before last
for (int i = 1; i < words.lengh - 1; ++i) {
sb.append(", ").append(word[i]);
}
// Check that there are at least two words
if (words.length > 1) {
// Handle the last word with an "and"
sb.append(" and ").append(words[1])
}
}

you don't need to use List and ListIterator (in this case!)
this is my solution!
ps: I don't undestand why the method is Static, i think in this casa is not necessary because we don't work on any static variables.
public static String formatWords(String[]words){
//Usefull to build the final resoult
StringBuilder sb = new StringBuilder();
/*start to put the word in the string builder
from the first to the last*/
for (int i = 0; i < words.length; i++) {
//put the wordat position i in string builder
sb.append(words[i]);
/*if the word is the 2 last and there are egual or more than
2 elements in words array
we can add the "and"*/
if(i==words.length-2 && words.length>=2) {
sb.append(" and ");
/*if the word is not the last put a comma
(actually we put a comma when there are more thand 3 item in words, but not in the last)
*/
}else if(i<words.length-1 ){
sb.append(", ");
}
/*if word[i] is the last of the array words we don't use nobody of the if!*/
/*this code word on 0 1,2,3 ore more word in array words!*/
}
return sb.toString();
}

replaceAll(",$", "and"); doesn't do what you think. It cannot find the last , in the string.
Try this
while(wordIter.hasNext()) {
//your code
}
if (words.length > 1) {
int indexOfLastComma = out.length() - words[words.length - 1].length();
return out.replace(indexOfLastComma - 1, indexOfLastComma, " and ").toString();
}
return out.toString();
We find the index of the last Comma and then replace it with and in its place.
Here's a fun way using Streams
String tempResult = IntStream.range(0, words.length - 1)
.mapToObj(i -> words[i])
.collect(Collectors.joining(","));
return words.length > 1 ? tempResult + " and " + words[words.length - 1] : words[0];
EDIT:
To filter out empty words, you can use a filter. Now checking words.length > 1 at the end will no longer work (since it can have empty strings). So, I'm checking if the tempResult has atleast one ,.
Here is a complete solution
String tempResult = Arrays.stream(words)
.filter(word -> !word.isEmpty())
.collect(Collectors.joining(","));
int indexOfLastComma = tempResult.lastIndexOf(',');
return indexOfLastComma != -1 ? tempResult.substring(0, indexOfLastComma) + " and "
+ tempResult.substring(indexOfLastComma + 1): tempResult;
It creates substring - so not the most efficient solution.

Related

why are some words not checked or included in string of reversed words?

everyone. I have a task- reverse every word in a sentence as long as the word is 5 or more letters long. The program has been working with most words, but after a couple, the words are not included. Does anyone know why this is happening? Here is the code:
public static int wordCount(String str) {
int count = 0;
for(int i = 0; i < str.length(); i++) if(str.charAt(i) == ' ') count++;
return count + 1;
}
This just gets the word count for me, which I use in a for loop later to loop through all the words.
public static String reverseString(String s) {
Stack<Character> stack = new Stack<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
stack.push(s.charAt(i));
}
while (!stack.empty()) {
sb.append(stack.pop());
}
return sb.toString();
}
This reverses a single string. This is not where I reverse certain words- this reverses a string. "Borrowed" from https://stackoverflow.com/a/33458528/16818831.
Lastly, the actual function:
public static String spinWords(String sentence) {
String ans = "";
for(int i = 0; i <= wordCount(sentence); i++) {
if(sentence.substring(0, sentence.indexOf(' ')).length() >= 5) {
ans += reverseString(sentence.substring(0, sentence.indexOf(' '))) + " ";
sentence = sentence.substring(sentence.indexOf(' ') + 1);
} else {
ans += sentence.substring(0, sentence.indexOf(' ')) + " ";
sentence = sentence.substring(sentence.indexOf(' ') + 1);
}
}
return ans;
}
This is where my mistake probably is. I'd like to know why some words are omitted. Just in case, here is my main method:
public static void main(String[] args) {
System.out.println(spinWords("Why, hello there!"));
System.out.println(spinWords("The weather is mighty fine today!"));
}
Let me know why this happens. Thank you!
The main issue would appear to be the for loop condition in spinWords()
The word count of your sentence keeps getting shorter while at the same time, i increases.
For example:
i is 0 when the word count is 5
i is 1 when the word count is 4
i is 2 when the word count is 3
i is 3 when the word count is 2 which
stops the loop.
It can't get through the whole sentence.
As many have mentioned, using the split method would help greatly, for example:
public static String spinWords(String sentence) {
return Arrays.asList(sentence.split(" ")).stream()
.map(word -> word.length() < 5 ? word : new StringBuilder(word).reverse().toString())
.collect(Collectors.joining(" "));
}
I think you should rewrite a lot of your code using String.split(). Instead of manually parsing every letter, you can get an array of every word just by writing String[] arr = sentence.split(" "). You can then use a for loop to go through and reverse each word something like this
for (int i=0; i<arr.length; i++) {
if (arr[i] >= 5) {
arr[i] = reverse(arr[i])
}
}
I know you just asked for a solution to your current code, but this would probably get you a better grade :)

Check if a sentence has the same words forward and backwards

I am trying to check if a sentence is the same forwards and backwards or a "sentence palindrome." The sentence "You can cage a swallow, can't you, but you can't swallow a cage, can you?" should return (True) as a palindrome. Ignore everything that is not a letter.
My problem: Not sure how to compare words specifically. This currently works for words checking if they are palindromes, but I need to figure out what to change to compare each word.
public static boolean isWordPalindrome(String input) {
Deque<Character> q = new LinkedList<>( );
Deque<Character> q2 = new LinkedList<>( );
Character letter; // One character from the input string
int mismatches = 0; // Number of spots that mismatched
int i; // Index for the input string
int x;
for (i = 0; i < input.length( ); i++)
{
letter = input.charAt(i); // read next character in the string
if (letter.toString().equals(',') || letter.toString().equals('"') || letter.toString().equals('?') || letter.toString().equals('!') || letter.toString().equals('.') || letter.toString().equals(' ')) {
//throwaway.add(letter); //ignore above chars and put in throwaway stack
}
if (Character.isLetter(letter)) // if letter put into q's
{
q.add(letter);
q2.addFirst(letter);
}
} // end of for loop
System.out.println("q: " + q);
System.out.println("q2:" + q2);
while (!q.isEmpty( ))
{
if (!Objects.equals(q.remove(), q2.remove()))
mismatches++;
}
I'd remove all the special characters, split the string by whitespaces and check the list is "symmetrical":
private static boolean isSentancePalindrom(String sentence) {
String[] words = sentence.replaceAll("[^a-zA-Z ]", "").split("\\s+");
for (int i = 0; i < words.length / 2; ++i) {
if (!words[i].equalsIgnoreCase(words[words.length - i - 1])) {
return false;
}
}
return true;
}
I came up with this:
public static boolean checkString(String str) {
str = str.replaceAll("[,\\?\\.!]+", "").toUpperCase();
String[] split = str.split(" ");
String[] reverse = new String[split.length];
System.arraycopy(split, 0, reverse, 0, split.length);
List<String> listOfSring = Arrays.asList(split);
List<String> reversListOfSring = Arrays.asList(reverse);
Collections.reverse(reversListOfSring);
return reversListOfSring.equals(listOfSring);
}
I hope it would help!

Creating longer array if elements contain whitespaces? (Java)

currently I'm trying to make a method that does the following:
Takes 3 String Arrays (words, beforeList, and afterList)
Looks for words that are in both words and in beforeList, and if found, replaces with word in afterList
Returns a new array that turns the elements with characters in afterList into new elements by themselves
For example, here is a test case, notice that "i'm" becomes split into two elements in the final array "i" and "am":
String [] someWords = {"i'm", "cant", "recollect"};
String [] beforeList = {"dont", "cant", "wont", "recollect", "i'm"};
String [] afterList = {"don't", "can't", "won't", "remember", "i am"};
String [] result = Eliza.replacePairs( someWords, beforeList, afterList);
if ( result != null && result[0].equals("i") && result[1].equals("am")
&& result[2].equals("can't") && result[3].equals("remember")) {
System.out.println("testReplacePairs 1 passed.");
} else {
System.out.println("testReplacePairs 1 failed.");
}
My biggest problem is in accounting for this case of whitespaces. I know the code I will post below is wrong, however I've been trying different methods. I think my code right now should return an empty array that is the length of the first but accounted for spaces. I realize it may require a whole different approach. Any advice though would be appreciated, I'm going to continue to try and figure it out but if there is a way to do this simply then I'd love to hear and learn from it! Thank you.
public static String[] replacePairs(String []words, String [] beforeList, String [] afterList) {
if(words == null || beforeList == null || afterList == null){
return null;
}
String[] returnArray;
int countofSpaces = 0;
/* Check if words in words array can be found in beforeList, here I use
a method I created "inList". If a word is found the index of it in
beforeList will be returned, if a word is not found, -1 is returned.
If a word is found, I set the word in words to the afterList value */
for(int i = 0; i < words.length; i++){
int listCheck = inList(words[i], beforeList);
if(listCheck != -1){
words[i] = afterList[listCheck];
}
}
// This is where I check for spaces (or attempt to)
for(int j = 0; j < words.length; j++){
if(words[j].contains(" ")){
countofSpaces++;
}
}
// Here I return an array that is the length of words + the space count)
returnArray = new String[words.length + countofSpaces];
return returnArray;
}
Here's one of the many ways of doing it, assuming you have to handle cases where words contain more than 1 consecutive spaces:
for(int i = 0; i < words.length; i++){
int listCheck = inList(words[i], beforeList);
if(listCheck != -1){
words[i] = afterList[listCheck];
}
}
ArrayList<String> newWords = new ArrayList<String>();
for(int i = 0 ; i < words.length ; i++) {
String str = words[i];
if(str.contains(' ')){
while(str.contains(" ")) {
str = str.replace(" ", " ");
}
String[] subWord = str.split(" ");
newWords.addAll(Arrays.asList(subWord));
} else {
newWords.add(str);
}
}
return (String[])newWords.toArray();

Tokenize method: Split string into array

I've been really struggling with a programming assignment. Basically, we have to write a program that translates a sentence in English into one in Pig Latin. The first method we need is one to tokenize the string, and we are not allowed to use the Split method usually used in Java. I've been trying to do this for the past 2 days with no luck, here is what I have so far:
public class PigLatin
{
public static void main(String[] args)
{
String s = "Hello there my name is John";
Tokenize(s);
}
public static String[] Tokenize(String english)
{
String[] tokenized = new String[english.length()];
for (int i = 0; i < english.length(); i++)
{
int j= 0;
while (english.charAt(i) != ' ')
{
String m = "";
m = m + english.charAt(i);
if (english.charAt(i) == ' ')
{
j++;
}
else
{
break;
}
}
for (int l = 0; l < tokenized.length; l++) {
System.out.print(tokenized[l] + ", ");
}
}
return tokenized;
}
}
All this does is print an enormously long array of "null"s. If anyone can offer any input at all, I would reallllyyyy appreciate it!
Thank you in advance
Update: We are supposed to assume that there will be no punctuation or extra spaces, so basically whenever there is a space, it's a new word
If I understand your question, and what your Tokenize was intended to do; then I would start by writing a function to split the String
static String[] splitOnWhiteSpace(String str) {
List<String> al = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (char ch : str.toCharArray()) {
if (Character.isWhitespace(ch)) {
if (sb.length() > 0) {
al.add(sb.toString());
sb.setLength(0);
}
} else {
sb.append(ch);
}
}
if (sb.length() > 0) {
al.add(sb.toString());
}
String[] ret = new String[al.size()];
return al.toArray(ret);
}
and then print using Arrays.toString(Object[]) like
public static void main(String[] args) {
String s = "Hello there my name is John";
String[] words = splitOnWhiteSpace(s);
System.out.println(Arrays.toString(words));
}
If you're allowed to use the StringTokenizer Object (which I think is what the assignment is asking, it would look something like this:
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
which will produce the output:
this
is
a
test
Taken from here.
The string is split into tokens and stored in a stack. The while loop loops through the tokens, which is where you can apply the pig latin logic.
Some hints for you to do the "manual splitting" work.
There is a method String#indexOf(int ch, int fromIndex) to help you to find next occurrence of a character
There is a method String#substring(int beginIndex, int endIndex) to extract certain part of a string.
Here is some pseudo-code that show you how to split it (there are more safety handling that you need, I will leave that to you)
List<String> results = ...;
int startIndex = 0;
int endIndex = 0;
while (startIndex < inputString.length) {
endIndex = get next index of space after startIndex
if no space found {
endIndex = inputString.length
}
String result = get substring of inputString from startIndex to endIndex-1
results.add(result)
startIndex = endIndex + 1 // move startIndex to next position after space
}
// here, results contains all splitted words
String english = "hello my fellow friend"
ArrayList tokenized = new ArrayList<String>();
String m = "";
int j = 0; //index for tokenised array list.
for (int i = 0; i < english.length(); i++)
{
//the condition's position do matter here, if you
//change them, english.charAt(i) will give index
//out of bounds exception
while( i < english.length() && english.charAt(i) != ' ')
{
m = m + english.charAt(i);
i++;
}
//add to array list if there is some string
//if its only ' ', array will be empty so we are OK.
if(m.length() > 0 )
{
tokenized.add(m);
j++;
m = "";
}
}
//print the array list
for (int l = 0; l < tokenized.size(); l++) {
System.out.print(tokenized.get(l) + ", ");
}
This prints, "hello,my,fellow,friend,"
I used an array list since at the first sight the length of the array is not clear.

Would there be an approach without using a regular expression?

This is an interview question from
http://www.glassdoor.com/Interview/Indeed-Software-Engineer-Interview-Questions-EI_IE100561.0,6_KO7,24.htm , specifically, the problem
"The asked me a method that took in a string and return words up to the max length. There could be any amount of spaces which made it a little tricky "
Here is my solution(with test case)
public class MaxLength {
public static void main(String[] args) {
List<String> allWords = maxWords("Jasmine has no love for chris", 2);
for(String word: allWords){
System.out.println(word);
}
}
public static List<String> maxWords(String sentence, int length) {
String[] words = sentence.trim().split("\\s+");
List<String> list = new ArrayList<String>();
for(String word: words) {
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
The test ran fine and i got my expected output - no. However during an actual interview, I think the interviewer doesn't expect you to know this regular expression off the top of your head (I didn't had to find it from How do I split a string with any whitespace chars as delimiters?)
Is there another approach to this problem without using regular expressions?
Try:
public static List<String> maxWords(String sentence, int length) {
List<String> list = new ArrayList<String>();
String tmp = sentence;
while (tmp.indexOf(" ") != -1) {
String word = tmp.substring(0,tmp.indexOf(" "));
tmp = tmp.substring(tmp.indexOf(" ")+1);
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
You could use the StringTokenizer.
Another, maybe more lengthy approach would be to iterate over the string and use the methods provided by the Character class (Character.isWhiteSpace(char c)) and break the string accordingly.
Well, you could try something like this :
Doesn't create many subStrings() just creates subStrings of "matched" Strings
public class Test {
public static void main(String[] args) {
String s = "Jasmine has no love for chris";
s=s.trim();
List<String> ls = getMaxLength(s, 3);
for (String str : ls) {
System.out.println(str);
}
}
static List<String> getMaxLength(String s, int length) {
List<String> ls = new ArrayList<String>();
int i = 0;
if (s.charAt(i + length) == ' ' || i + length == s.length()) { // search if first word matches your criterion.
for (i = 1; i < length; i++) { // check for whitespace between 0 and length
if (s.charAt(i) == ' ') {
i = length;
break;
}
if (i == length - 1)
ls.add(s.substring(0, length));
}
}
for (i = length; i < s.length(); i++) {// start search from second word..
if (s.charAt(i - 1) == ' ' && i + length < s.length() // if char at length is space or end of String, make sure the char before the current char is a space.
&& (s.charAt(i + length) == ' ' || i + length == s.length())) {
for (int j = i; j < i + length; j++) {
if (s.charAt(j) == ' ') {
i = i + length;
break;
}
if (j == i + length - 1) {
ls.add(s.substring(i, i + length));
}
}
}
}
return ls;
} // end of method
}

Categories

Resources