Array entries from string don't map to the hash - ruby

I am very new to Ruby, and programming in general. Firstly, I have the below code:
hashy = {"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 6, "f" => 6}
array = ["a", "b", "c"]
string = "df"
array.push (string.split(//))
puts array
test = array.map {|a| hashy.select {|k,v| a == k}}
puts test
This code successfully maps 'a', 'b' and 'c' to the hash, and populates test with the keys and values from the hash.
This always works for a pre-defined array. However if I add to the array from a string (in this case the string "df", or create an array from a string, it no longer maps the array values to the hash, and I can't see why. I've looked at different ways of populating the array with the string values, but each time get the same problem.
As far as I can see "df" should also be mapping to the hash.
Any help would be greatly appreciated.

It's because you pushing string.split(//) array to array as one object, so you have one array element among the numbers in array as result.
array = ["a", "b", "c"]
string = "df"
array.push (string.split(//))
=> ["a", "b", "c", ["d", "f"]]
To avoid this, you can use array concatenation, for example
array = ["a", "b", "c"]
string = "df"
array += string.split(//)
=> ["a", "b", "c", "d", "f"]

Related

How can I split Hash keys into 2 or more arrays based on keys which contain same values?

Say I made a Hash like this: ["ab" => "a", "ac" => "a", "cd" => "c", "ce" => "c", "df" => "d"]
and I need to split this into 3 arrays like these: ["ab", "ac"], ["cd", "ce"], ["df"]. Split my Hash into 3 arrays based on keys which has same values.
How can I do this?
you can use group by on a hash and group by the values this will return a hash with the value as a key and all hashes with the same value in an array then transform the values and take the first element in each array of that value (wich would be the key of the original objects)
hash.group_by { |key, value| value }.transform_values(&:first).values
[1] pry(main)> {"ab" => "a", "ac" => "a", "cd" => "c", "ce" => "c", "df" => "d"}.group_by { |key, value| value }.transform_values(&:first).values
=> [["ab", "a"], ["cd", "c"], ["df", "d"]]
Input
a={"ab" => "a", "ac" => "a", "cd" => "c", "ce" => "c", "df" => "d"}
Code
p a.group_by{|_,v|v}
.values
.map{|arr|arr.map(&:first)}
output
[["ab", "ac"], ["cd", "ce"], ["df"]]

using each_slice and sort Ruby

I need to reorganize an array into slices of 2 elements and then sort each slice alphabetically using each_slice
I've managed to get the each_slice correctly but I can seem to then sort each sub array.
What am I doing wrong here?
array.each_slice(2).to_a { |el| el = el.sort}
You just need to create a new array with the output that you want.
For instance:
# $ array = ["b", "a", "d", "c", "k", "l", "p"]
arr = []
array.each_slice(2) { |el| arr << el.sort}
# $ arr
# => [["a", "b"], ["c", "d"], ["k", "l"], ["p"]]
EDIT:
Pointed in the comments (by #mu is too short), you can also do:
arr = array.each_slice(2).map(&:sort)

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"

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.

Why does the Array allocation my_arr[0,3] work while my_arr[3,0] fails?

I want to pull two values out from an array based on their index.
Unfortunately this fails when the last index is zero and I don't undertand why.
my_array = ["a", "b", "c", "d", "e", "f", "g"]
my_array[1,2]
# => ["b", "c"]
my_array[0,2]
# => ["a", "b"]
my_array[2,0]
# => []
Why does the last allocation fail to pull out elements 2 and 0?
I suspect my operation is not in fact doing what I think at all since adding a third index makes the whole thing fail:
my_array[1,2,3]
# => ArgumentError: wrong number of arguments (3 for 1..2)
What am I actually doing with the array[var1, var2] syntax and what should I be doing?
my_array[start,length][docs] is the slice syntax:
returns a subarray starting at start and continuing for length elements
This is a short syntax for my_array.slice(start, length);
You should do this instead:
my_array.values_at(2, 0)
=> ["c", "a"]
See Array#values_at and Array#slice

Resources