-1

Given a non-empty string and an int N, return the string made starting with char 0, and then every Nth char of the string. So if N is 3, use char 0, 3, 6, ... and so on. N is 1 or more.

 everyNth("Miracle", 2) → "Mrce"
 everyNth("abcdefg", 2) → "aceg"
 everyNth("abcdefg", 3) → "adg"

This code isn't actually compiling. But after putting a couple of breakpoints and running in debug mode, it's showing it will return an ASCII value of "77" instead of a string value at the str.charAt() position. I am not sure why. Please help.

I am trying to learn and understand the fundemental logic behind how to solve this problem.

I know you can use Stringbuilder and append each value to buffer than print the values is one way getting the answer. So I want to avoid using any pre-defined classes, that will perform the logic in the background.

Attempt: I've tried to convert the String type to char also, but same result.

public static String everyNth(String str, int n){
    String charAtPosition = "";
    int x = 0, pos = 0;
    String finalString = "";
    String stringPosition = str.charAt(pos); <-- Getting ASCII value instead of string value for ex. in "Miracle" string input, it should return "M"
    charAtPosition = stringPosition * n;
    for(int i = 0; i < str.length(); i++){
        finalString = finalString + charAtPosition;
    }
    return finalString;
}
Roy
  • 73
  • 2
  • 8
  • 3
    Is `String stringPosition = str.charAt(pos);` compiling? And `charAtPosition = stringPosition * n;`? – ernest_k Mar 29 '21 at 21:42
  • No, it's actually not compiling. I've posted this issue based on me running in debug mode. – Roy Mar 30 '21 at 00:45
  • 1
    Replace `String stringPosition = str.charAt(pos)` with `String stringPosition = String.valueOf(str.charAt(0))`. You can not assign a `char` value to a `String` variable. – Arvind Kumar Avinash Mar 30 '21 at 12:51

2 Answers2

5

Your code does not compile. First of all, replace String stringPosition = str.charAt(pos) with String stringPosition = String.valueOf(str.charAt(0)) as str.charAt(pos) returns a char value which you can not assign to a String variable.

Also, it is as simple as starting the loop counter with 0 and stepping with a value n. In each iteration, append the character at the loop counter to a StringBuilder.

public final class Main {

    public static final void main(String[] args) {
        System.out.println(everyNth("Miracle", 2));
        System.out.println(everyNth("abcdefg", 2));
        System.out.println(everyNth("abcdefg", 3));
    }

    public static String everyNth(String str, int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i += n) {
            sb.append(str.charAt(i));
        }
        return sb.toString();
    }
}

Output:

Mrce
aceg
adg

You can use String instead of StringBuilder but I recommend you use StringBuilder instead of String for such a case because repeated string concatenation in a loop creates additional as many instances of String as the number of concatenation. Check this discussion to learn more about it.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
1

Here is an approach using a lambda and streams.

  • Iterate every nth integer starting with 0
  • Map the nth character
  • Convert to a string
BiFunction<String, Integer, String> everyNth =
        (s, n) -> IntStream
                .iterate(0, i -> i < s.length(), i -> i + n)
                .mapToObj(i -> s.charAt(i) + "")
                .reduce("", (a, b) -> a + b).toString();

Some test data and a run

Map<String, Integer> testData =
        Map.of("Miracle", 2, "abcdefgh", 2, "abcdefg", 3, "a",
                4, "programming", 4, "notchanging", 1);

testData.forEach((k, v) -> System.out.printf("Every %s, %-12s -> %s%n",
        v, k, everyNth.apply(k, v)));

prints

Every 2, Miracle      -> Mrce
Every 4, programming  -> pri
Every 2, abcdefgh     -> aceg
Every 4, a            -> a
Every 1, notchanging  -> notchanging
Every 3, abcdefg      -> adg
WJS
  • 36,363
  • 4
  • 24
  • 39
  • 2
    I would write `BiFunction everyNth = (s, n) -> IntStream.iterate(0, i -> i < s.length(), i -> i + n).mapToObj(i -> String.valueOf(s.charAt(i))).reduce("", String::concat);`. The reason why I would prefer `String.valueOf(s.charAt(i))` over `s.charAt(i) + ""` is that the later sounds like concatenation whereas the former sounds like conversion. Some other improvements in this code are: using method reference, and removing the redundant `toString`. All the same, the problem with this solution is that it will produce the output in different order on each execution. – Arvind Kumar Avinash Mar 30 '21 at 08:49
  • If you look at the OP's comment and the rationale for closing, it makes sense. The code doesn't compile. The OP does quite a few things incorrectly here ->`String stringPosition = str.charAt(pos); ` and the statement following. – WJS Mar 30 '21 at 12:55
  • You can directly use `.collect(Collectors.joining())` instead of `.reduce("", (a, b) -> a + b).toString()`. – Unmitigated Mar 30 '21 at 21:41
  • @ArvindKumarAvinash Using `LinkedHashMap` will fix the output order issue. – Unmitigated Mar 30 '21 at 21:44
  • @iota Yes I know. I thought I commented on using `Collectors.joining()`. Apparently that comment was removed. And the output order is irrelevant (not part of the requirement). Even if I use a `LinkedHashMap`, Map.of() will still change the order. – WJS Mar 30 '21 at 21:51