1

Is it possible to group a string every nth character?

For example, suppose I have a string containing the following: "Hello how are you"

What I'm trying to do is if the user inputs 4, then based on the integer, break into 4 groups and assign those to strings.

1 2 3 4 1 2 3 4 1 2 3 4 1 2
H E L L O H O W A R E Y O U

All the letters that has 1 assigned will be group 1, similarly, all the letters that has 2 assigned will be group 2.

Group 1 - "HOAO", Group 2 - "EHRU", Group 3 - "LOE", Group 4 - "LWY"

Below is what I have so far

import java.util.*; 

class groupChar {

    static void groupLetters(String str, int n) {
        String result="";
        for(int i = 0; i < str.length(); i = i + n){
          result = result + str.charAt(i);
        }
        System.out.println(result);
      }


      public static void main(String[] args) {

        Scanner inputMessage = new Scanner(System.in);
        System.out.println("Enter string : ");
        String message = inputMessage.nextLine();

        System.out.println("Enter a number : ");
        Scanner inputNumber = new Scanner(System.in);
        int number = Integer.parseInt(inputNumber.nextLine());
        
        System.out.println("String is - " + message);
        System.out.println("Number is - " + number);

        groupLetters(message, number);

      }
}

So far I'm only able to create one group based on the user input.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
jillatik
  • 25
  • 4
  • https://stackoverflow.com/questions/5455794/removing-whitespace-from-strings-in-java then use modulo to assign the letters – Martheen Aug 01 '22 at 05:10
  • use array of strings, add the character to specific index based on group and also use modulo operator for limiting the index to number of groups – deadshot Aug 01 '22 at 05:10
  • Take care of java naming conventions. Class names should start with upper case character – Jens Aug 01 '22 at 05:14
  • @AlexanderIvanchenko its grouped based on the number assigned to the letter. All the letters that has number 1 assigned, will be group 1. The letters that has number 2 assigned, will be the second group etc.. – jillatik Aug 01 '22 at 05:25
  • @jillatik OK, can you please [*add this clarification*](https://stackoverflow.com/posts/73189022/edit) to the question. – Alexander Ivanchenko Aug 01 '22 at 05:28
  • @Martheen - thanks, I have implemented the remove whitespace part, but sorry I do not understand what you mean by use modulo to assign the letters. – jillatik Aug 01 '22 at 05:35
  • Loop through each character and `index % groupCount` would be the group for that character. Remember that we're using 0-based indexing here. – Martheen Aug 01 '22 at 05:39

3 Answers3

1

You can approach this problem using Map to track all the groups and using StringBuilder to construct the individual group.

Firstly, we need to generate a HashMap populated with entries having the keys corresponding to the indices of the groups and empty StringBuilders as *values.

Then we have to iterate over the given string, maintaining two indices: i - position in the string and groupId - index of the group. At iteration step, we need to update the current group by appending the current character.

That's how it can be implemented:

public static Map<Integer, StringBuilder> groupLetters(String str, int n) {
    Map<Integer, StringBuilder> groupByGroupId = createGroups(n);
    for (int i = 0, groupId = 1; i < str.length(); i++, groupId = (groupId++ % n) + 1) {
        groupByGroupId.get(groupId).append(str.charAt(i));
    }
    return groupByGroupId;
}

public static Map<Integer, StringBuilder> createGroups(int n) {
    Map<Integer, StringBuilder> groupByGroupId = new HashMap<>();
    for (int i = 1; i <= n; i++) {
        groupByGroupId.put(i, new StringBuilder());
    }
    return groupByGroupId;
}

main

public static void main(String[] args) {
    for (Map.Entry<Integer, StringBuilder> entry: groupLetters("hellohowareyou", 4).entrySet()) {
        System.out.println("Group " + entry.getKey() + " -> " + entry.getValue());
    }
}

Output:

Group 1 -> hoao
Group 2 -> ehru
Group 3 -> loe
Group 4 -> lwy
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
  • Thanks a bunch for this. It works for me, I shall take some time to learn all the new things I found in your answer which will help me to digest and understand the whole thing hopefully :) – jillatik Aug 01 '22 at 08:00
  • @jillatik Sure, if you don't have much experience with Collections, I suggest you this [*tutorial developed by Oracle*](https://docs.oracle.com/javase/tutorial/collections/intro/index.html) and if you have a text-book - use it as well. Collections are very important of the Java Core. – Alexander Ivanchenko Aug 01 '22 at 10:17
0

The suggested solution would be to use a map or dictionary with <int,List>. But I recommend the most simple and understandable way without using Map based on your code.

I used the same example as you provided, but starting from 0 would make it easier to understand the code.

0 1 2 3 4 5 6 7 8 9 10 11 12 13
0 1 2 3 0 1 2 3 0 1  2  3  0  1
H E L L O H O W A R  E  Y  O  U

The Algorithm:

  • Group 1 : 0,(0 + (1 x 4)),(0 + (2 x 4)),(0 + (3 x 4)) ...
  • Group 2 : 1,(1 + (1 x 4)),(1 + (2 x 4)),(1 + (3 x 4)) ...
  • Group 3 : 2,(2 + (1 x 4)),(2 + (2 x 4)),(2 + (3 x 4)) ...

Therefore, Group a+1 : a, (a + (1 x N)), (a + (2 x N)), (a + (3 x N))... WHERE the total number of elements in each group is

(total number of Char in string) / (number of droup) + 1

Code

We used a for loop for a AND a for loop for the increment 1,2,3...

Therefore, I have modified your code to meet the requirement :

static void groupLetters(String str,int n) {
    //Remove the string space and to UPPER CASE
    str = str.toUpperCase().replaceAll("\\s+","");
    for(int a = 0; a < n; a++){
        String result = "";

        //Get the Char in Group a with the algorithm mentioned above
        for(int i = 0; i < str.length() / n + 1; i++){
            if(a + (i * n) < str.length()){
                result = result + str.charAt(a + (i * n));
            }
        }

        System.out.println("Group "+ (a + 1) + ": " + result);
    }
}


public static void main(String[] args) {

    Scanner inputMessage = new Scanner(System.in);
    System.out.println("Enter string : ");
    String message = inputMessage.nextLine();

    System.out.println("Enter a number of group gonna break into : ");
    Scanner inputNumber = new Scanner(System.in);
    int number = Integer.parseInt(inputNumber.nextLine());

    System.out.println("String is - " + message);
    System.out.println("Number of Group is - " + number);

    groupLetters(message,number);

}

OUTPUT:

String is - Hello how are you
Number of Group is - 4
Group 1: HOA
Group 2: EHR
Group 3: LOE
Group 4: LWY
Pyuan07
  • 1
  • 2
  • That's a brute-force solution with a time complexity **O(n ^ 2)** because of the use of string-concatenation, which causes the string representing a group to be copied initially at each step of iteration of the inner loop. – Alexander Ivanchenko Aug 01 '22 at 06:19
  • Thanks for this answer! May I ask what the "/ n + 1; i++" represent in the for loop "for(int i = 0; i < str.length() / n + 1; i++)" ? – jillatik Aug 01 '22 at 07:59
0

Splitter can be used to split text by length

com.google.common.base.Splitter , see -> https://www.geeksforgeeks.org/splitter-class-guava-java/

I slightly modified the code :

import java.util.Scanner;
import com.google.common.base.Splitter;

public class test {
  public static String result="";
  public static int index = 0;
  static void groupLetters(String str, int n) {
    str = str.replaceAll("\\s", "");
    Iterable<String> fullString = Splitter.fixedLength(n).split(str);
    int length = str.length() % n == 0 ? str.length() / n : (str.length() / n) + 1;
    for(int i = 0; i < length + 1; i++){
        fullString.forEach(s->{
            if(s.length()>index){
                result+=s.charAt(index)+"";
            }
        });
        result+=" ";
        index++;
    }

    System.out.println(result);
  }
  public static void main(String[] args) {

    Scanner inputMessage = new Scanner(System.in);
    System.out.println("Enter string : ");
    String message = inputMessage.nextLine();

    System.out.println("Enter a number : ");
    Scanner inputNumber = new Scanner(System.in);
    int number = Integer.parseInt(inputNumber.nextLine());
    
    System.out.println("String is - " + message);
    System.out.println("Number is - " + number);

    groupLetters(message, number);
    
  }
}
Omar Hussien
  • 313
  • 1
  • 9