3

so I'm working on this problem: https://www.hackerrank.com/challenges/30-review-loop/problem (it's in C#)

and so far I'm just trying to break it down piece by piece, and so far I was able to get it to show every other character, but I'm not sure how to concatenate each letter into a new string.

My code for the problem is as follows I've commented out the two for loops, because I felt like there was a more elegant solution to this than what I had, but I didn't want to lose where I was in case another path proved to be more challenging.

using System;
using System.Collections.Generic;
using System.IO;
class Solution {
    static void Main(String[] args) {
        /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution */
        int inputQTY = Int32.Parse(Console.ReadLine());
        string input = Console.ReadLine(); // The example gives us the first word to be Hacker then the next word Rank on the next line, so the outputs would be Hce akr, and Rn ak respectively.
        int strLen = input.Length;
        char[] inputCharArray = input.ToCharArray();
        string output = "";

        /*
        for (int j = 0; j < inputQTY; j++){

            for (int i = 0; i < strLen; i++) {
                if (j % 2 == 0 && i % 2 == 0) {
                    Console.WriteLine(inputCharArray[i]);
                    output = new string (new char[] {inputCharArray[i]});
                    Console.WriteLine(output);
                    Console.WriteLine("This is i: {0}", i);
                    Console.WriteLine("This is j: {0}", j);
                    Console.WriteLine("--------------");
                    Console.WriteLine("");
                }
                else {
                    Console.WriteLine("This is the next j part hopefully: {0}", j);
                }
            } 
        }*/




    }
}

Like I understand I need to first step through the word, grab every other letter, then step through the word again and grab the remaining letters, then concatenate those letters into words, and concatenate those words into a sentence, so j would be the loop giving me the two words where I is the loop getting the two words put together..... but I'm having a difficult time wrapping my head around where I'm going wrong here. On top of this, I feel like there's another approach entirely that I'm missing, using commands I may not even know about.

Anyhoo any help is appreciated, hopefully I won't be so green after this. Thanks!

Ok so I ended up solving it with the following code, thank you for all your help everyone!

I ended up solving it with the following code (in C#):

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

class Solution {
    static void Main(String[] args) {
        /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution */
        int count = Int32.Parse(Console.ReadLine());
        for (int k = 0; k < count; k++) {
            char[] word = Console.ReadLine().ToCharArray();
            StringBuilder sb1 = new StringBuilder();
            StringBuilder sb2 = new StringBuilder();
            for (int i = 0; i < word.Length; i+=2) {
                sb1.Append(word[i]);
            }
            for (int j = 1; j < word.Length; j+=2) {
                sb2.Append(word[j]);
            }
            Console.WriteLine(sb1 + " " + sb2);
        }
    }
}
glitchwizard
  • 421
  • 1
  • 6
  • 23
  • Use `+` or something [here](https://stackoverflow.com/questions/21078/most-efficient-way-to-concatenate-strings). – user202729 Jan 25 '18 at 06:05

3 Answers3

5

LINQ version, updated to fix index error:

output = $"{new string(s.Where((x,i) => i % 2 == 0).ToArray())} {new string(s.Where((x,i) => i % 2 != 0).ToArray())}";

To explain, you're grabbing every character whose index in the string is evenly divisible by 2 and printing it, then every character in the string whose index is not evenly divisible by 2 and printing it.

Update:

Since I was asked for further explanation. First, here's the full code that runs successfully in the HackerRank challenge:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    class Solution
    {
        static void Main(String[] args)
        {
            List<string> tests = new List<string>();
            var testCount = int.Parse(Console.ReadLine());
            for (var i = 0; i < testCount; i++)
            {
                tests.Add(Console.ReadLine());
            }
            foreach (var s in tests)
            {
                Console.WriteLine($"{new string(s.Where((x, i) => i % 2 == 0).ToArray())} {new string(s.Where((x, i) => i % 2 != 0).ToArray())}");
            }
        }
    }

Regarding what each section of the code does:

i % 2 == 0

This is a test to see if a number is evenly divisible by two, or an even number.

s.Where((x,i) => i % 2 == 0)

This says, for the array of characters that make up the string 's', return all characters (the result is an IEnumerable) where that character's index (location in the string) is an even number.

new string(s.Where((x,i) => i % 2 == 0).ToArray())

This says to take that IEnumerable of characters with even numbered indexes and return them to an Array of characters. Then, create a new string out of that array of characters.

For the odd numbers, it's the same, but you use != 0 in the mod.

Randy Slavey
  • 544
  • 4
  • 19
  • 3
    if the same character is repeated, indexOf will fetch the first – levent Jan 25 '18 at 07:10
  • 1
    Right you are, @levent. Fixed. – Randy Slavey Jan 25 '18 at 07:33
  • Thank you Randy, I think I need a little more help. I added the using System.Linq, and then copied and pasted that code in (I don't really understand all of the operators you used or what each one does, though I'm trying to look it all up now) And I get the error : Unexpected symbol `class' That's really weird to me I think..... why would it not know what a class is? I don't fully understand Linq, as this is the first time I've ever seen it. I'm really starting pretty well towards the beginning of learning all of this, so any help or explanation is very much appreciated. – glitchwizard Jan 26 '18 at 04:22
  • 1
    I honestly don't know why you're getting the error. I pasted my code into HackerRank and it was successful. I'll try to break down my explanation a bit more. – Randy Slavey Jan 26 '18 at 08:21
  • @RandySlavey, I forgot a stupid semicolon lol *facepalm* That explanation you gave is awesome!! Thank you! – glitchwizard Jan 27 '18 at 01:22
2

I used this simple method of appending to two StringBuilder objects

var sb1 = new StringBuilder();
var sb2 = new StringBuilder();
int i = 0;
foreach (char c in input)
{
    var sb = (i % 2 == 0 ? sb1 : sb2);
    sb.Append(c);
    i = i + 1;
}
output = sb1.ToString() + " " + sb2.ToString();
dodgy_coder
  • 12,407
  • 10
  • 54
  • 67
  • Thanks dodgy. Can you break down and explain the arguments at this line: var sb = (i % 2 == 0 ? sb1 : sb2); What's the ? mean, and how does that relate to sb1 and sb2? Does that operator command it to put it in one or the other depending on true or false? thanks! ~G – glitchwizard Jan 26 '18 at 04:24
  • I ended up solving it with a variation of this, but I think you and I did the same thing ( I even used your sb1 & sb2 because it made a lot of sense). I was reluctant to use StringBuilder because for some reason I felt like there had to be another way to do it because I've used python and ruby, and they have such simple ways of appending arrays. I didn't realize C# doesn't have that and you need to use this stringbuilder thing – glitchwizard Jan 26 '18 at 05:50
  • 1
    @glitchwizard Hi yes you're right - StringBuilder is the best way to do it as its is efficient when adding and removing characters from it. A String is immutable - creates another String in memory every time you append a character to it. With the line var sb = (i % 2 ... yes this is called an inline if statement. Its exactly equivalent to doing this ... StringBuilder sb; if (i % 2 == 0) { sb = sb1; } else { sb = sb2; } – dodgy_coder Jan 26 '18 at 08:20
  • thank you! Much appreciated on the explanation there. I'll have to dig more into inline statements. – glitchwizard Jan 27 '18 at 01:19
2

this is the long way..

   int count =  int.Parse(Console.ReadLine());
    for(int k = 0; k < count; k++){
        char[] inputChars = Console.ReadLine().ToCharArray();
        char[] evenChars = new char[inputChars.Length % 2 == 0 ? inputChars.Length / 2 : (inputChars.Length + 1) / 2];
        char[] oddChars = new char[inputChars.Length - evenChars.Length];
        int evenIndex=0,oddIndex = 0;
        for(int i = 0; i < inputChars.Length;i++)
            if(i % 2 == 0)
                evenChars[evenIndex++] = inputChars[i];
            else
                oddChars[oddIndex++] = inputChars[i];
        Console.WriteLine(string.Format("{0} {1}",string.Concat(evenChars),string.Concat(oddChars)));
    }

an alternative..

   int count =  int.Parse(Console.ReadLine());
    for(int k = 0; k < count; k++){
        string input = Console.ReadLine();
         Enumerable.Range(0, input.Length)
            .OrderBy(o => o % 2 != 0)
            .Select(o => {
                if(o == 1)
                   Console.Write(" ");
                Console.Write(input[o]);
                return input[o];
            }).ToArray();
        Console.Write("\n");
    }
levent
  • 3,464
  • 1
  • 12
  • 22