I want to find all the combinations of a string preserving the order . Is there any built in method in Ruby to achieve this?
For example, "abcd".all_combinations should give the output:
a
b
c
d
ab
bc
cd
abc
bcd
abcd
Probably not the ideal implementation, but this works:
def combinations(str)
items = str.chars
(1..items.length).map { |i| items.each_cons(i).map(&:join) }.flatten
end
Also check Enumerable#each_cons. You can also just add it to the String class like this:
class String
def combinations
items = self.chars
(1..items.length).map { |i| items.each_cons(i).map(&:join) }.flatten
end
end
'abcd'.combinations
What is happening:
We make the string an actual array of characters with String#chars.
Then for each number i between 1 to the length of the string:
Call Enumerable#each_cons which basically returns the possible combinations of the length i as an array of characters too. So if i is 2, then the result of items.each_cons(2) will be [ ['a', 'b'], ['b', 'c'], ['c', 'd'] ]
The .map(&:join) part is basically calling Array#join on each of the elements of that array of arrays, so it becomes ['ab', 'bc', 'cd']
The result of (1..items.length).map { |i| items.each_cons(i).map(&:join) } is: [ ['a', 'b', 'c', 'd'], ['ab', 'bc', 'cd'], ['abc', 'bcd'], ['abcd'] ] which is an array of arrays. We call Array#flatten on it to make it a simple array (read the flatten link for more).
There is no builtin function that does exactly what you're looking for.
String#each_cons looks interesting as Tamer points out.
Here's an alternate solution:
def all_combos(str)
1.upto(str.length) do |segment_length|
0.upto(str.length - segment_length) do |starting_point|
puts str[starting_point, segment_length]
end
end
end
all_combos("abcd")
The starting and ending indices of the sub-strings form a pattern of a combination with repetition, for which Ruby does have a built-in method.
class String
def all_combinations
idx = (0 ... self.size).to_a
idx.repeated_combination(2){|i,j| yield self[i..j]}
end
end
"abcd".all_combinations{|combo| puts combo}
Related
def compute(ary)
return nil unless ary
ary.map { |a, b| !b.nil? ? a + b : a }
end
compute([1,2],[3,4])
Can someone please explain to me how compute adds the inner array's values?
To me it seems that calling map on that array of arrays would add the two arrays together, not the inner elements of each array.
map basically iterates over the elements of the object:
foo = [
['a', 'b'],
['c', 'd']
]
foo.map{ |ary| puts ary.join(',') }
# >> a,b
# >> c,d
In this example it's passing each sub-array, which is assigned to ary.
Looking at it a bit differently:
foo.map{ |ary| puts "ary is a #{ary.class}" }
# >> ary is a Array
# >> ary is a Array
Because Ruby lets us assign multiple values at once, that could have been written:
foo.map{ |item1, item2| puts "item1: #{ item1 }, item2: #{ item2 }" }
# >> item1: a, item2: b
# >> item1: c, item2: d
If map is iterating over an array of hashes, each iteration yields a sub-hash to the block:
foo = [
{'a' => 1},
{'b' => 2}
]
foo.map{ |elem| puts "elem is a #{ elem.class }" }
# >> elem is a Hash
# >> elem is a Hash
If map is iterating over a hash, each iteration yields the key/value pair to the block:
foo = {
'a' => 1,
'b' => 2
}
foo.map{ |k, v| puts "k: #{k}, v: #{v}" }
# >> k: a, v: 1
# >> k: b, v: 2
However, if you only give the block a single parameter, Ruby will assign both the key and value to the variable so you'll see it as an array:
foo.map{ |ary| puts "ary is a #{ary.class}" }
# >> ary is a Array
# >> ary is a Array
So, you have to be aware of multiple things that are happening as you iterate over the container, and as Ruby passes the values into map's block.
Beyond all that, it's important to remember that map is going to return a value, or values, for each thing passed in. map, AKA collect, is used to transform the values. It shouldn't be used as a replacement for each, which only iterates. In all the examples above I didn't really show map used correctly because I was trying to show what happens to the elements passed in. Typically we'd do something like:
foo = [['a', 'b'], ['c', 'd']]
foo.map{ |ary| ary.join(',') }
# => ["a,b", "c,d"]
Or:
bar = [[1,2], [3,4]]
bar.collect{ |i, j| i * j }
# => [2, 12]
There's also map! which changes the object being iterated, rather than returns the values. I'd recommend avoiding map! until you're well aware of why it'd be useful to you, because it seems to confuse people no end unless they understand how variables are passed and how Arrays and Hashes work.
The best thing is to play with map in IRB. You'll be able to see what's happening more easily.
I think I figured this out myself.
map selects the first array of the array-of-arrays and pipes it into the block. The variables a and b therefore refer to the first array's inner elements, rather than the first array and the second array in the array-of-arrays.
I need to reorder an array based on dependent elements. If an element is an array (has dependency), the second element of that array is the dependency, and will be required to come before that array. All dependency information is then removed as we don't need any more, and we return an array with corrected order.
# array1 = [['a'], ['b','c'], ['c','a']]
# ordered = ['a', 'c', 'b']
# logic: c comes before b, a comes before c
Here is my approach which I think is over-engineered:
array1.each_with_index do |ar, i|
# ignore elements without dependencies
if ar.count > 1
# get dependency
dep = ar[1]
# get index for element where this dependency is first
dep_index = array1.index { |a| a.first == dep }
# remove found dependency and store
dep_element = array1.delete_at(dep_index)
# insert found dependency to before current element
array1.insert(i, dep_element)
# delete processed dependency
ar.delete(dep)
end
end
The obvious problem with the above is that as I iterate through the array, elements which have dependencies I haven't processed will be shifted back, yet the loop will only be performed once. So, I introduced a while:
while array1.flatten.count > array1.count
However, my result is ['c', 'a', 'b'].
I have also been tasked to test for self-referential and circular (infinite) dependency loops. Should I have used an Enumerator? Should have I converted array to different structure (objects) to enable easier management of order?
Check out TSort, which comes with the Ruby standard library.
It performs a topological sort, which sounds like what you need. Using your example above:
require 'tsort'
class Hash
include TSort
alias tsort_each_node each_key
def tsort_each_child(node, &block)
fetch(node).each(&block)
end
end
def deps arr
arr.map { |head, *tail| {head => tail} }.reduce(&:merge).tsort
end
deps [['a'], ['b','c'], ['c','a']]
#=> ['a', 'c', 'b']
No need to reinvent the wheel, use Rake:
require 'rake'
ary = [[:a], [:b, :c], [:c, :a]]
ordered = []
ary.each { |head, *tail| task head => tail do ordered << head end }
task( main: ary.map( &:first ) ).invoke
ordered
#=> [:a, :c, :b]
Otherwise, there is an algo for this, but I forgot its name.
How would I write a case statement that would list all elements in an array, allow the user to pick one, and do processing on that element?
I have an array:
array = [ 'a', 'b', 'c', 'd' ]
Ultimately I'd like it to behave like this:
Choices:
1) a
2) b
3) c
4) d
Choice =>
After the user picks 3, I would then do processing based off the choice of the user. I can do it in bash pretty easily.
Ruby has no built-in menu stuff like shell scripting languages do. When doing menus, I favor constructing a hash of possible options and operating on that:
def array_to_menu_hash arr
Hash[arr.each_with_index.map { |e, i| [i+1, e] }]
end
def print_menu menu_hash
puts 'Choices:'
menu_hash.each { |k,v| puts "#{k}) #{v}" }
puts
end
def get_user_menu_choice menu_hash
print 'Choice => '
number = STDIN.gets.strip.to_i
menu_hash.fetch(number, nil)
end
def show_menu menu_hash
print_menu menu_hash
get_user_menu_choice menu_hash
end
def user_menu_choice choice_array
until choice = show_menu(array_to_menu_hash(choice_array)); end
choice
end
array = %w{a b c d}
choice = user_menu_choice(array)
puts "User choice was #{choice}"
The magic happens in array_to_menu_hash:
The [] method of Hash converts an array with the form [ [1, 2], [3, 4] ] to a hash {1 => 2, 3 => 4}. To get this array, we first call each_with_index on the original menu choice array. This returns an Enumerator that emits [element, index_number] when iterated. There are two problems with this Enumerator: the first is that Hash[] needs an array, not an Enumerator. The second is that the arrays emitted by the Enumerator have the elements in the wrong order (we need [index_number, element]). Both of these problems are solved with #map. This converts the Enumerator from each_with_index into an array of arrays, and the block given to it allows us to alter the result. In this case, we are adding one to the zero-based index and reversing the order of the sub-arrays.
I have an array of strings, and want to make a hash out of it. Each element of the array will be the key, and I want to make the value being computed from that key. Is there a Ruby way of doing this?
For example:
['a','b'] to convert to {'a'=>'A','b'=>'B'}
You can:
a = ['a', 'b']
Hash[a.map {|v| [v,v.upcase]}]
%w{a b c}.reduce({}){|a,v| a[v] = v.upcase; a}
Ruby's each_with_object method is a neat way of doing what you want
['a', 'b'].each_with_object({}) { |k, h| h[k] = k.upcase }
Here's another way:
a.zip(a.map(&:upcase)).to_h
#=>{"a"=>"A", "b"=>"B"}
Which ever way you look at it you will need to iterate the initial array. Here's another way :
a = ['a', 'b', 'c']
h = Hash[a.collect {|v| [v, v.upcase]}]
#=> {"a"=>"A", "b"=>"B", "c"=>"C"}
Here's a naive and simple solution that converts the current character to a symbol to be used as the key. And just for fun it capitalizes the value. :)
h = Hash.new
['a', 'b'].each {|a| h[a.to_sym] = a.upcase}
puts h
# => {:a=>"A", :b=>"B"}
From Rails 6.x, you can use Enumerable#index_with:
irb(main):002:0> ['a', 'b'].index_with {|s| s.upcase}
=> {"a"=>"A", "b"=>"B"}
Pass a block to .to_h
[ 'a', 'b' ].to_h{ |element| [ element, element.upcase ] }
#=> {"a"=>"A", "b"=>"B"}
Thanks to #SMAG for the refactor suggestion!
Not sure if this is the real Ruby way but should be close enough:
hash = {}
['a', 'b'].each do |x|
hash[x] = x.upcase
end
p hash # prints {"a"=>"A", "b"=>"B"}
As a function we would have this:
def theFunk(array)
hash = {}
array.each do |x|
hash[x] = x.upcase
end
hash
end
p theFunk ['a', 'b', 'c'] # prints {"a"=>"A", "b"=>"B", "c"=>"C"}
In Perl to perform a hash update based on arrays of keys and values I can do something like:
#hash{'key1','key2','key3'} = ('val1','val2','val3');
In Ruby I could do something similar in a more complicated way:
hash.merge!(Hash[ *[['key1','key2','key3'],['val1','val2','val3']].transpose ])
OK but I doubt the effectivity of such procedure.
Now I would like to do a more complex assignment in a single line.
Perl example:
(#hash{'key1','key2','key3'}, $key4) = &some_function();
I have no idea if such a thing is possible in some simple Ruby way. Any hints?
For the Perl impaired, #hash{'key1','key2','key3'} = ('a', 'b', 'c') is a hash slice and is a shorthand for something like this:
$hash{'key1'} = 'a';
$hash{'key2'} = 'b';
$hash{'key3'} = 'c';
In Ruby 1.9 Hash.[] can take as its argument an array of two-valued arrays (in addition to the old behavior of a flat list of alternative key/value arguments). So it's relatively simple to do:
mash.merge!( Hash[ keys.zip(values) ] )
I do not know perl, so I'm not sure what your final "more complex assignment" is trying to do. Can you explain in words—or with the sample input and output—what you are trying to achieve?
Edit: based on the discussion in #fl00r's answer, you can do this:
def f(n)
# return n arguments
(1..n).to_a
end
h = {}
keys = [:a,:b,:c]
*vals, last = f(4)
h.merge!( Hash[ keys.zip(vals) ] )
p vals, last, h
#=> [1, 2, 3]
#=> 4
#=> {:a=>1, :b=>2, :c=>3}
The code *a, b = some_array will assign the last element to b and create a as an array of the other values. This syntax requires Ruby 1.9. If you require 1.8 compatibility, you can do:
vals = f(4)
last = vals.pop
h.merge!( Hash[ *keys.zip(vals).flatten ] )
You could redefine []= to support this:
class Hash
def []=(*args)
*keys, vals = args # if this doesn't work in your version of ruby, use "keys, vals = args[0...-1], args.last"
merge! Hash[keys.zip(vals.respond_to?(:each) ? vals : [vals])]
end
end
Now use
myhash[:key1, :key2, :key3] = :val1, :val2, :val3
# or
myhash[:key1, :key2, :key3] = some_method_returning_three_values
# or even
*myhash[:key1, :key2, :key3], local_var = some_method_returning_four_values
you can do this
def some_method
# some code that return this:
[{:key1 => 1, :key2 => 2, :key3 => 3}, 145]
end
hash, key = some_method
puts hash
#=> {:key1 => 1, :key2 => 2, :key3 => 3}
puts key
#=> 145
UPD
In Ruby you can do "parallel assignment", but you can't use hashes like you do in Perl (hash{:a, :b, :c)). But you can try this:
hash[:key1], hash[:key2], hash[:key3], key4 = some_method
where some_method returns an Array with 4 elements.