using each_slice and sort Ruby - 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)

Related

Zip all array values of hash

I'd like to zip all the array values of a hash. I know there's a way to zip arrays together. I'd like to do that with the values of my hash below.
current_hash = {:a=>["k", "r", "u"],
:b=>["e", " ", "l"],
:c=>["d", "o", "w"],
:d=>["e", "h"]
}
desired_outcome = "keder ohulw"
I have included my desired outcome above.
current_hash.values.then { |first, *rest| first.zip(*rest) }.flatten.compact.join
An unfortunate thing with Ruby zip is that the first enumerable needs to be the receiver, and the others need to be parameters. Here, I use then, parameter deconstruction and splat to separate the first enumerable from the rest. flatten gets rid of the column arrays, compact gets rid of the nil (though it's not really necessary as join will ignore it), and join turns the array into the string.
Note that Ruby zip will stop at length of the receiver; so if :a is shorter than the others, you will likely have a surprising result. If that is a concern, please update with an example that reflects that scenario, and the desired outcome.
Here I'm fleshing out #Amadan's remark below the horizontal line in is answer. Suppose:
current_hash = { a:["k","r"], b:["e"," ","l"], c:["d","o","w"], d:["e", "h"] }
and you wished to return "keder ohlw". If you made ["k","r"] and [["e"," ","l"], ["d","o","w"], ["e", "h"]] zip's receiver and argument, respectively, you would get "keder oh", which omits "l" and "w". (See Array#zip, especially the 3rd paragraph.)
To include those strings you would need to fill out ["k","r"] with nils to make it as long as the longest value, or make zip's receiver an array of nils of the same length. The latter approach can be implemented as follows:
vals = current_hash.values
#=> [["k", "r"], ["e", " ", "l"], ["d", "o", "w"], ["e", "h"]]
([nil]*vals.map(&:size).max).zip(*vals).flatten.compact.join
#=> "keder ohlw"
Note:
a = [nil]*vals.map(&:size).max
#=> [nil, nil, nil]
and
a.zip(*vals)
#=> [[nil, "k", "e", "d", "e"],
# [nil, "r", " ", "o", "h"],
# [nil, nil, "l", "w", nil]]
One could alternatively use Array#transpose rather than zip.
vals = current_hash.values
idx = (0..vals.map(&:size).max-1).to_a
#=> [0, 1, 2]
vals.map { |a| a.values_at(*idx) }.transpose.flatten.compact.join
#=> "keder ohlw"
See Array#values_at. Note:
a = vals.map { |a| a.values_at(*idx) }
#=> [["k", "r", nil],
# ["e", " ", "l"],
# ["d", "o", "w"],
# ["e", "h", nil]]
a.transpose
#=> [["k", "e", "d", "e"],
# ["r", " ", "o", "h"],
# [nil, "l", "w", nil]]

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"

Split an array into new arrays (each with a unique name) [duplicate]

This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 7 years ago.
I'm trying to slice an array into equal sizes (rounded down) and save each section to respective variables.
The method each_slice has worked to grab n-sized blocks. However I can't think of a way to:
iterate over the each's blocks' "sub index"
create a new array for each and give each a unique name.
letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n"]
def groups_of_five(array)
split_array = array.each_slice(5).to_a
#something like the following:
#array(n) = Array[split_array.each {|x| x}]
end
end
The output I'm hoping for:
groups_of_five(letters)
=> array1: ["a,"b","c","d","e"]
=> array2: ["f","g","h","i","j"]
=> array3: ["k","l","m","n"]
Combine each_slice with with_index and you'll have everything you need:
letters.each_slice(5).with_index(1) do |group, index|
puts "array#{index}: #{group.inspect}"
end
Output is:
array1: ["a", "b", "c", "d", "e"]
array2: ["f", "g", "h", "i", "j"]
array3: ["k", "l", "m", "n"]
It's no longer possible to set local variable dynamically in Ruby versions greather than 1.8, so if you want to assign to variables it will have to be instance variables or you could output a Hash.
The following will create instance variables:
def groups_of_five(array)
array.each_slice(5).with_index(1) do |group, index|
instance_variable_set "#array#{index}".to_sym, group
end
end
groups_of_five(letters)
puts #array1 #=> ["a", "b", "c", "d", "e"]
puts #array2 #=> ["f", "g", "h", "i", "j"]
puts #array3 #=> ["k", "l", "m", "n"]
Or this will output a Hash:
def groups_of_five(array)
hash = {}
array.each_slice(5).with_index(1) do |group, index|
hash["array#{index}".to_sym] = group
end
hash
end
hash = groups_of_five(letters)
puts hash[:array1] #=> ["a", "b", "c", "d", "e"]
puts hash[:array2] #=> ["f", "g", "h", "i", "j"]
puts hash[:array3] #=> ["k", "l", "m", "n"]
If you are looking for a hash structure to return from groups_of_five(letters), here's the solution
def groups_of_five(array)
split_array = letters.each_slice(5).to_a
split_array.reduce({}){ |i,a|
index = split_array.index(a) + 1
i["array#{index}"] = a; i
}
end
# groups_of_five(letters)
#=> {"array1"=>["a", "b", "c", "d", "e"], "array2"=>["f", "g", "h", "i", "j"], "array3"=>["k", "l", "m", "n"]}
You could do this:
def group_em(a,n)
arr = a.dup
(1..(arr.size.to_f/n).ceil).each_with_object({}) { |i,h|
h["array#{i}"] = arr.shift(n) }
end
group_em(letters,1)
#=> {"array1"=>["a"], "array2"=>["b"],...,"array14"=>["n"]}
group_em(letters,2)
#=> {"array1"=>["a", "b"], "array2"=>["c", "d"],...,"array7"=>["m", "n"]}
group_em(letters,5)
#=> {"array1"=>["a", "b", "c", "d", "e"],
# "array2"=>["f", "g", "h", "i", "j"],
# "array3"=>["k", "l", "m", "n"]}
A variant is:
def group_em(arr,n)
(1..(arr.size.to_f/n).ceil).zip(arr.each_slice(n).to_a)
.each_with_object({}) { |(i,a),h| h["array#{i}"]=>a) }
end

Combining words in a string into anagrams using 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.

Ruby Hash to array of values

I have this:
hash = { "a"=>["a", "b", "c"], "b"=>["b", "c"] }
and I want to get to this: [["a","b","c"],["b","c"]]
This seems like it should work but it doesn't:
hash.each{|key,value| value}
=> {"a"=>["a", "b", "c"], "b"=>["b", "c"]}
Any suggestions?
Also, a bit simpler....
>> hash = { "a"=>["a", "b", "c"], "b"=>["b", "c"] }
=> {"a"=>["a", "b", "c"], "b"=>["b", "c"]}
>> hash.values
=> [["a", "b", "c"], ["b", "c"]]
Ruby doc here
I would use:
hash.map { |key, value| value }
hash.collect { |k, v| v }
#returns [["a", "b", "c"], ["b", "c"]]
Enumerable#collect takes a block, and returns an array of the results of running the block once on every element of the enumerable. So this code just ignores the keys and returns an array of all the values.
The Enumerable module is pretty awesome. Knowing it well can save you lots of time and lots of code.
It is as simple as
hash.values
#=> [["a", "b", "c"], ["b", "c"]]
this will return a new array populated with the values from hash
if you want to store that new array do
array_of_values = hash.values
#=> [["a", "b", "c"], ["b", "c"]]
array_of_values
#=> [["a", "b", "c"], ["b", "c"]]
hash = { :a => ["a", "b", "c"], :b => ["b", "c"] }
hash.values #=> [["a","b","c"],["b","c"]]
There is also this one:
hash = { foo: "bar", baz: "qux" }
hash.map(&:last) #=> ["bar", "qux"]
Why it works:
The & calls to_proc on the object, and passes it as a block to the method.
something {|i| i.foo }
something(&:foo)

Resources