Alexander Swann
Alexander Swann

Reputation: 639

Remove same number of duplicate characters for each character in a string

How would it be possible to remove the same number of duplicates for each character in a string until only one instance is left of one of the characters stopping the process of removing duplicates from the remaining characters?

If I have a string:

string = "aaaabbbxxxxx44444oooooo9999999"

You can see that the character b is the character with the least number of duplicates (i.e. there's b followed by two more bs) so, if we remove 2 duplicates from each character set, we'd be left with the following without losing any characters used in the original string but minimising the number of duplicates for each character:

string = "aabxxx444oooo99999"

Also lets assume our string contains no white space and if it is jumbled:

string_b = "aabb4keekkk447abae777err99r9"

You can sort it first:

string_b = stringb.chars.sort.join
#=> string_b = "4447777999aaaabbbeeeekkkkrrr"

Before applying your reduce duplicates method:

string_b = "4779aabeekkr"

Upvotes: 0

Views: 1054

Answers (2)

Jon Snow
Jon Snow

Reputation: 11882

You should put this in a method.

def convert str
    return str if str.empty?
    letter_array = str.chars.group_by {|x| x}.values
    drop_size = letter_array.map(&:size).min - 1
    letter_array.map {|x| x.drop drop_size}.join
end

To run this in irb console

2.2.1 :230 > convert 'aaaabbbxxxxx44444oooooo9999999'
=> "aabxxx444oooo99999"
2.2.1 :231 > convert ''
=> ""
2.2.1 :232 > convert 'abc'
=> "abc"
2.2.1 :233 > convert 'abcabcddd'
=> "abcdd"
2.2.1 :234 > convert "    "
=> " "

You want to test with various inputs (eg empty string) to make sure that it works.

Upvotes: 1

Silver Phoenix
Silver Phoenix

Reputation: 521

If you don't require the original order or chars, then you can do:

string_b = "aabb4keekkk447abae777err99r9"
h = string_b.chars.group_by { |c| c }.map { |c, a| [c, a.size] }.to_h
#=> {"a"=>4, "b"=>3, "4"=>3, "k"=>4, "e"=>4, "7"=>4, "r"=>3, "9"=>3}
# #to_h is optional here

n = h.values.min - 1
#=> 3
# use map(&:last) instead of #values if not using #to_h previously

h.map { |k, v| k * (v - n) }.sort.join
#=> "4779aabeekkr"

Upvotes: 2

Related Questions