0

I have been trying to solve this problem for a while now, im supposed to take a given string like "aaabbc" and compress it into a new string that states multiples of a letter in a row in place. So it would output "3a2bc"

So far i managed to print it out except it counts all instances of a letter and im not sure how to get rid of the current repeats:

def compress_str(str)

    new_str = []
    word = str.split("")

    word.each do |char|
        count = 0
        word.each do |ele|
            if ele == char
                count += 1
            end
        end
        if count > 1
          new_str << count
          new_str << char
        else
          new_str << char
        end
    end

    return new_str.join("")

Example output:

Sample

Any suggestions on how I'm supposed to get rid of them?

3 Answers 3

1

Using Enumerable#chunk might be a good fit for your needs.

uncompressed = %w(aaabbcddaaaaa aaabb 111ddttttabaaacc)

uncompressed.each do |str|
  puts str.chars.chunk{|e| e}.map {|e| "#{e[1].length}#{e[0]}"}.join
end

>>> 3a2b1c2d5a
>>> 3a2b
>>> 312d4t1a1b3a2c

Sure, you can add another check inside map block, so omit 1 before a single element and print as is.

Sign up to request clarification or add additional context in comments.

Comments

1

You could use String#chars (1), so Enumerable#chunk_while (2), then Enumerable#flat_map (3) into the desired format and finally Array#join:

str = "aaabbcaa"

str.chars.chunk_while { |x, y| x == y }.flat_map { |e| [(e.size unless e.size == 1), e.first] }.join
#=> "3a2bc2a"

Step by step

# (1)
str.chars#.to_a
#=> ["a", "a", "a", "b", "b", "c", "a", "a"]

so

# (2)
str.chars.chunk_while { |x, y| x == y }#.to_a
#=> [["a", "a", "a"], ["b", "b"], ["c"], ["a", "a"]]

then

# (3)
str.chars.chunk_while { |x, y| x == y }.flat_map { |e| [(e.size unless e.size == 1),e.first] }
#=> [3, "a", 2, "b", nil, "c", 2, "a"]

Comments

1

String#scan can also be handy here.

uncompressed = %w(aaabbcddaaaaa aaabb 111ddttttabaaacc)
uncompressed.map { |w| w.scan(/(.)(\1*)/).map(&:join) }
#⇒ [["aaa", "bb", "c", "dd", "aaaaa"],
#   ["aaa", "bb"],
#   ["111", "dd", "tttt", "a", "b", "aaa", "cc"]]

And to get the desired outcome.

uncompressed.map do |w|
  w.scan(/(.)(\1*)/).map(&:join).map do |l|
    "#{l.length}#{l[0]}"
  end.join
end
#⇒ ["3a2b1c2d5a", "3a2b", "312d4t1a1b3a2c"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.