How to combine 2 strings from an array without repeats in Ruby? - ruby

In Ruby, what's an elegant way to combine 2 strings from an array without repeating them?
Example:
array = ['one', 'two', 'three', 'four']
And I want my output to be:
['onetwo', 'onethree', 'onefour', 'twothree', 'twofour', 'threefour']
Seems simple enough but I've been pretty stumped!
Edit: this is for doing something with anagrams so order does not matter. ('onetwo' ends up being equivalent to 'twoone'.)

You can use Arrary#combination, Enumerable#map and Array#join for that.
Code
array.combination(2).map(&:join)
#=> ["onetwo", "onethree", "onefour", "twothree", "twofour", "threefour"]
Explanation
array = ['one', 'two', 'three', 'four']
a = array.combination(2)
#=> #<Enumerator: ["one", "two", "three", "four"]:combination(2)>
To view the contents of the enumerator:
a.to_a
#=> [["one", "two" ], ["one", "three"], ["one" , "four"],
# ["two", "three"], ["two", "four" ], ["three", "four"]]
Then
a.map(&:join)
which has the same effect as:
a.map { |e| e.join }
#=> ["onetwo", "onethree", "onefour", "twothree", "twofour", "threefour"]
If you wanted "twoone" as well as "onetwo", use Array#permutation instead of combination:
array.permutation(2).map(&:join)
#=> ["onetwo" , "onethree", "onefour" , "twoone" , "twothree", "twofour",
# "threeone", "threetwo", "threefour", "fourone", "fourtwo" , "fourthree"]

Related

Looking to convert information from a file into a hash Ruby

Hello I have been doing some research for sometime on this particular project I have been working on and I am at a loss. What I am looking to do is use information from a file and convert that to a hash using some of those components for my key. Within the file I have:1,Foo,20,Smith,40,John,55
An example of what I am looking for I am looking for an output like so {1 =>[Foo,20], 2 =>[Smith,40] 3 => [John,55]}
Here is what I got.
h = {}
people_file = File.open("people.txt") # I am only looking to read here.
until people_file.eof?
i = products_file.gets.chomp.split(",")
end
people_file.close
FName = 'test'
str = "1,Foo,20,Smith, 40,John,55"
File.write(FName, str)
#=> 26
base, *arr = File.read(FName).
split(/\s*,\s*/)
enum = (base.to_i).step
arr.each_slice(2).
with_object({}) {|pair,h| h[enum.next]=pair}
#=> {1=>["Foo", "20"], 2=>["Smith", "40"],
# 3=>["John", "55"]}
The steps are as follows.
s = File.read(FName)
#=> "1,Foo,20,Smith, 40,John,55"
base, *arr = s.split(/\s*,\s*/)
#=> ["1", "Foo", "20", "Smith", "40", "John", "55"]
base
#=> "1"
arr
#=> ["Foo", "20", "Smith", "40", "John", "55"]
a = base.to_i
#=> 1
I assume the keys are to be sequential integers beginning with a #=> 1.
enum = a.step
#=> (1.step)
enum.next
#=> 1
enum.next
#=> 2
enum.next
#=> 3
Continuing,
enum = a.step
b = arr.each_slice(2)
#=> #<Enumerator: ["Foo", "20", "Smith", "40", "John", "55"]:each_slice(2)>
Note I needed to redefine enum (or execute enum.rewind) to reinitialize it. We can see the elements that will be generated by this enumerator by converting it to an array.
b.to_a
#=> [["Foo", "20"], ["Smith", "40"], ["John", "55"]]
Continuing,
c = b.with_object({})
#=> #<Enumerator: #<Enumerator: ["Foo", "20", "Smith", "40", "John", "55"]
# :each_slice(2)>:with_object({})>
c.to_a
#=> [[["Foo", "20"], {}], [["Smith", "40"], {}], [["John", "55"], {}]]
The now-empty hashes will be constructed as calculations progress.
c.each {|pair,h| h[enum.next]=pair}
#=> {1=>["Foo", "20"], 2=>["Smith", "40"], 3=>["John", "55"]}
To see how the last step is performed, each initially directs the enumerator c to generate the first value, which it passes to the block. The block variables are assigned to that value, and the block calculation is performed.
enum = a.step
b = arr.each_slice(2)
c = b.with_object({})
pair, h = c.next
#=> [["Foo", "20"], {}]
pair
#=> ["Foo", "20"]
h #=> {}
h[enum.next]=pair
#=> ["Foo", "20"]
Now,
h#=> {1=>["Foo", "20"]}
The calculations are similar for the remaining two elements generated by the enumerator c.
See IO::write, IO::read, Numeric#step, Enumerable#each_slice, Enumerator#with_object, Enumerator#next and Enumerator#rewind. write and read respond to File because File is a subclass of IO (File.superclass #=> IO). split's argument, the regular expression, /\s*,\s*/, causes the string to be split on commas together with any spaces that surround the commas. Converting [["Foo", "20"], {}] to pair and h is a product of Array Decompostion.

Ruby array of strings: split into smallest pieces

I would like to know if there is a method in Ruby that splits an Array of String in smallest pieces. Consider:
['Cheese crayon', 'horse', 'elephant a b c']
Is there a method that turns this into:
['Cheese', 'crayon', 'horse', 'elephant', 'a', 'b', 'c']
p ['Cheese crayon', 'horse', 'elephant a b c'].flat_map(&:split)
# => ["Cheese", "crayon", "horse", "elephant", "a", "b", "c"]
None that I know of. But you can split each string individually and then flatten the results into a single array:
p ['Cheese crayon', 'horse', 'elephant a b c'].map(&:split).flatten
You can do it this way:
array.map { |s| s.split(/\s+/) }.flatten
This splits your string by any number of whitespace characters. As far as I know, it's the default behavior of split without any arguments, so you can shorten it to:
array.map(&:split).flatten
['Cheese crayon', 'horse', 'elephant a b c'].join(' ').split
# => ["Cheese", "crayon", "horse", "elephant", "a", "b", "c"]

Remove duplicates conditionally from array in Ruby [duplicate]

This question already has answers here:
Remove redundant or duplicate tuples in Ruby array
(6 answers)
Closed 9 years ago.
So i have this array:
['One', 'Two', 'One', 'One', 'Three', 'Three', 'One']
I want to get this result:
['One', 'Two', 'One', 'Three', 'One']
So I want to remove items that is the same as previous item.
How to do that in Ruby?
Use Enumerable#chunk
ary = ['One', 'Two', 'One', 'One', 'Three', 'Three', 'One']
ary.chunk {|x| x }.map(&:first)
#=> ["One", "Two", "One", "Three", "One"]
Enumerable#chunk enumerates over the items, chunking them together based on the return value of the block. consecutive elements which return the same block value are chunked together.
ary.chunk {|x| x }.to_a
=> [["One", ["One"]],
["Two", ["Two"]],
["One", ["One", "One"]],
["Three", ["Three", "Three"]],
["One", ["One"]]]
map(&:first) Array#map iterates over the array calling the first method on each element of the array
&:first is called symbol to proc which creates a proc object that map yields each element of the array to
so the example above could be rewritten as below:
lambda_obj = ->(ele) { ele.first }
ary.chunk {|x| x }.map(&lambda_obj)
#=> ["One", "Two", "One", "Three", "One"]
Pretty straightforward with inject:
ary.inject [] do |accum,x|
accum.last == x ? accum : accum << x
end

How can I merge two hashes?

I made two hashes hash1 and hash2 with following keys and values.
Input:
hash1 = {1=>"One", 2=>"Two", 3=>"Three"}
hash2 = {4=>"First", 5=>"Second", 6=>"Third"}
Result:
And I am expecting hash3 to give me a result like
hash3 #=> {1 => "One", 2 => "Two", 3 => "Three", 4 => "First", 5 => "Second", 6 => "Third"}
Can anyone tell me how I can merge these two hashes? Assume that hash3 should contain all keys and all values.
Solution with minimal coding
hash3 = hash1.merge(hash2)
It seems you are looking for Hash#merge
hash1 = {1=>"One", 2=>"Two", 3=>"Three"}
hash2 = {4=>"First", 5=>"Second", 6=>"Third"}
hash3 = hash1.merge hash2
#=> {1 => "One", 2 => "Two", 3 => "Three", 4 => "First", 5 => "Second", 6 => "Third"}
Considering the fact that you access your hash through an increasing sequence of integers, you should think about using an Array instead of a Hash.
result = hash1.values + hash2.values
# => ["One", "Two", "Three", "First", "Second", "Third"]
This way you can still access your values similarly (e.g. result[2] #=> "Three"), but you have a more concise data structure.
If you want 1 to return both "first" and "one", you'll need to store them in an array which will then be the value of which 1 maps to.
results = {}
hash1.each do |key, value|
if results[key].nil?
results[key] = [value]
else
results[key] << value
hash2.each do |key, value|
if results[key].nil?
results[key] = [value]
else
results[key] << value
results[1]
=> ["one", "first"]
Update
You obviously don't want a hash. You want an array with the values only.
results = hash1.values + hash2.values
=> ["one", "two", "three", "first", "second", "third"]
You can access this array just like a hash. Keep in mind that arrays are zero-indexed, so:
results[0]
=> "one"
results[2]
=> "three"
results[5]
=> "third"
Update 2
And now you want a hash after all, because you have unique keys. So:
hash3 = hash1.merge(hash2)
Since you're learning a new language and are still learning how things work. I'd suggest that with whatever you're working with you take a look at the developer docs.
http://ruby-doc.org/
From there you can search for whatever you're looking for and find other interesting things you can do with the Objects ruby provides for you.
To answer your question specifically you'll need merge method for hashes.
{1: 'One', 2: 'Two', 3: 'Three'}.merge(4: 'Four', 5: 'Five', 6: 'Six)
Will yield {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five', 6: 'Six'}

Combining two arrays into a hash

I'm trying to combine two arrays into a hash.
#sample_array = ["one", "Two", "Three"]
#timesheet_id_array = ["96", "97", "98"]
I want to output the results into a hash called #hash_array. Is there a simple way to combine the two in a code block so that if you call puts at the end it looks like this in the console
{"one" => "96", "Two" => "97", "Three" => "98"}
I think this could be done in one or two lines of code.
try this
keys = [1, 2, 3]
values = ['a', 'b', 'c']
Hash[keys.zip(values)]
thanks
#hash_array = {}
#sample_array.each_with_index do |value, index|
#hash_array[value] = #timesheet_id_array[index]
end
Imho that looks best:
[:a,:b,:c].zip([1,2,3]).to_h
# {:a=>1, :b=>2, :c=>3}
Dr. Nic suggests 2 options explained well at http://drnicwilliams.com/2006/10/03/zip-vs-transpose/
#hash_array = {}
0.upto(#sample_array.length - 1) do |index|
#hash_array[#sample_array[index]] = #timesheet_id_array[index]
end
puts #hash_array.inspect

Resources