Combining words in a string into anagrams using ruby - ruby

I wanted to make a program in which I would be able to sort and store the characters which are anagrams into individual groups. For ex for the string:
"scream cars for four scar creams" the answer should be:
[["scream", "creams"], ["cars", "scar"], ["for"], ["four"]]
For the above I used the code:
here = self.split()
there = here.group_by { |x| x.downcase.chars.sort}.values
And I got the required answer. But when I change the code to:
here = self.split()
there = here.group_by { |x| x.downcase.chars.sort}
I get the answer:
{["a", "c", "e", "m", "r", "s"]=>["scream", "creams"], ["a", "c", "r", "s"]=>["cars", "scar"], ["f", "o", "r"]=>["for"], ["f", "o", "r", "u"]=>["four"]}
I would like to know that why it is like this now? I got to the answer using hit-and-trial method.

As commented by Yevgeniy Anfilofyev , values is a method and hence it
Returns a new array populated with the values from hash
While, if we remove the method values then we get the whole hash and not only the array of values.

Related

How to extract each individual combination from a flat_map?

I'm fairly new to ruby and it's my first question here on stackoverflow so pardon me if I'm being a complete noob.
The code which i am working with contains this line -
puts (6..6).flat_map{|n| ('a'..'z').to_a.combination(n).map(&:join)}
What the code does is that its starts printing each of the combinations starting from "abcdef" and continues till the end (which i have never seen as it has 26^6 combinations).
Of course having an array of that size (26^6) is unimaginable hence I was wondering if there is any way by which i can get next combination in a variable, work with it, and then continue on to the next combination ?
For example I calculate the first combination as "abcdef" and store it in a variable 'combo' and use that variable somewhere and then the next combination is calculated and "abcdeg" is stored in 'combo' and hence the loop continues ?
Thanks
(6..6).flat_map { |n| ... } doesn't do much. Your code is equivalent to:
puts ('a'..'z').to_a.combination(6).map(&:join)
To process the values one by one, you can pass a block to combination:
('a'..'z').to_a.combination(6) do |combo|
puts combo.join
end
If no block is given, combination returns an Enumerator that can be iterated by calling next:
enum = ('a'..'z').to_a.combination(6)
#=> #<Enumerator: ["a", "b", "c", ..., "w", "x", "y", "z"]:combination(6)>
enum.next
#=> ["a", "b", "c", "d", "e", "f"]
enum.next
#=> ["a", "b", "c", "d", "e", "g"]
enum.next
#=> ["a", "b", "c", "d", "e", "h"]
Note that ('a'..'z').to_a.combination(6) will "only" yield 230,230 combinations:
('a'..'z').to_a.combination(6).size
#=> 230230
As opposed to 26 ^ 6 = 308,915,776. You are probably looking for repeated_permutation:
('a'..'z').to_a.repeated_permutation(6).size
#=> 308915776
Another way to iterate from "aaaaaa" to "zzzzzz" is a simple range:
('aaaaaa'..'zzzzzz').each do |combo|
puts combo
end
Or manually by calling String#succ: (this is what Range#each does under the hood)
'aaaaaa'.succ #=> "aaaaab"
'aaaaab'.succ #=> "aaaaac"
'aaaaaz'.succ #=> "aaaaba"

How to break down a string that's in an array even further

I'm trying to break down a sentence that's part of one string, but break it down into letters in their own array and have that inside one big array.
So what I mean is:
def break("hello world")
the code in the method would than result in this:
[["h","e","l","l","o], ["w","o","r","l","d"]]
The reason why I need it like that is so I can rearrange the letters in the order I want later. I've tried several things, but no luck.
"hello world".split.map &:chars
# => [["h", "e", "l", "l", "o"], ["w", "o", "r", "l", "d"]]
I wouldn't use break as a method name. It's a key word in the language.
def break_it(str)
str.split.map { |word| word.each_char.to_a }
end
break_it("hello world")

How to convert a string to an array of chars in ruby?

Let's say that you have a string "Hello" and you want an array of chars in return ["H", "e", "l", "l", "o"].
Although it's a simple question I couldn't find a direct answer.
There are several ways to get an array out of a String. #chars which is a shortcut for thestring.each_char.to_a is the most direct in my opinion
>> "Hello".chars
=> ["H", "e", "l", "l", "o"]
The are other ways to get the same result like "Hello".split(//) but they are less intention-revealing.

Format data in string to array?

I need to convert data from a string to an array. The string looks like this:
{a,b,c{1,2,3},d,e,f{11,22,33},g}
The array that I want to receive should look like this:
[a, b, c1, c2, c3, d, e, f11, f22, f33, g]
I tried to use the split method but it works poorly.
arr = str.split(' ');
keys = arr[0][2..-2]
keys = keys.split(',')
Do you have any ideas how it could be implemented?
Here's what I'd use:
string = '{a,b,c{1,2,3},d,e,f{11,22,33},g}'
array = string.scan(/[a-z](?:{.+?})?/).flat_map{ |s|
if s['{']
prefix = s[0]
values = s.scan(/\d+/)
([prefix] * values.size).zip(values).map(&:join)
else
s
end
}
array # => ["a", "b", "c1", "c2", "c3", "d", "e", "f11", "f22", "f33", "g"]
Here's how it works:
string.scan(/[a-z](?:{.+?})?/) # => ["a", "b", "c{1,2,3}", "d", "e", "f{11,22,33}", "g"]
returns the string broken into chunks, looking for a single letter followed by an optional string of { with some text then }.
values = s.scan(/\d+/) # => ["1", "2", "3"], ["11", "22", "33"]
As it's running in flat_map, if { is found, the numbers are scanned out.
([prefix] * values.size).zip(values).map(&:join) # => ["c1", "c2", "c3"], ["f11", "f22", "f33"]
And then an array of the prefix, with the same number of elements as there are values is created and zipped together, resulting in:
[["c", "1"], ["c", "2"], ["c", "3"]], [["f", "11"], ["f", "22"], ["f", "33"]]
The join glues those sub-arrays together. And flat_map flattens any subarrays created so the resulting output is a single array.
You need to arr = str.split(',') in the first step, because there is no whitespace between the values.
Also keep in mind you have {} to handle too.
This worked for me with simple regex and gsubing (though Tin Man's solution is better ruby):
def my_string_to_array(input_string)
groups = input_string.scan(/\w+\{.*?\}/)
groups.each do |group|
modified = group.gsub(',', ",#{group.match(/\w+/)[0]}").delete("{}")
input_string.gsub!(group, modified)
end
created_array = input_string.delete("{}").split(',')
end
string = '{a,b,c{1,2,3},d,e,f{11,22,33},g}'
my_string_to_array(string)
=> ["a", "b", "c1", "c2", "c3", "d", "e", "f11", "f22", "f33", "g"]
The way it works is that it first finds the groups having alphabets followed by braces and digits (like c{1,2,3})
For each such group, it modifies it by gsubing ',' with ',<alphabet>' and removing the braces.
Next, it replaces these groups with the modified ones in the original string.
And finally it removes the starting and ending braces in the original string, and converts it into an array.

Is there a one liner to destructively use `.split(//)` (e.g. turn string into array)?

So far I have:
my_array = "Foo bar na nas"
my_array.delete!(" ").downcase!
my_array = my_array.split(//).uniq
To get:
==> ["f", "o", "b", "a", "r", "n", "s"]
I can't seem to use .split!(//) like .delete! or .downcase! but I want to do all of this in one step. Is it possible?
Using my_array.delete!(" ").downcase!.split!(//) yields "': undefined method 'split!' for nil:NilClass" so I assume .split! just doesn't exist.
No. If you will read documentation you will get that destructive methods return nil when there is nothing to change, so you cannot chain them. If you want to change string to array of it's letters excluding whitespces you should rathe run:
my_array = "Foo bar na nas".downcase.gsub(/\W/, '').split(//).uniq
There also don't exist destructive method split!. Just how can it exist? Ruby is strong-typed language so you cannot change String into Array because they aren't related.
my_array.downcase.gsub(' ','').chars.uniq
Why not use split with a regular expression matching white space or nothing?
"Foo bar na nas".downcase.split(/\s*/).uniq
This returns
["f", "o", "b", "a", "r", "n", "s"]
split! does not exist because by convention methods with ! alter the object itself in ruby, and you can not coerce a string into an array because ruby is strongly typed.
"Foo bar na nas".downcase.split(//).uniq.keep_if { |item| item != " " }
#=> ["f", "o", "b", "a", "r", "n", "s"]
"Foo bar na nas t p".downcase.split(//).uniq.keep_if { |item| item != " " }
#=> ["f", "o", "b", "a", "r", "n", "s", "t", "p"]

Resources