How can I find the missing letter in an array - ruby

Given an array of letters arr = ["a","b","c","d","f"], I would like to construct an array containing all letters between the smallest and largest letters (by ASCII value) in arr that are not contained in arr. Here that would be ["e"]. How can I to that?

a = %w[a b c d f]
(a.min..a.max).to_a - a # => ["e"]

Assuming that the letters in the array are within "a" to "z" and ordered alphabetically, you could fetch the array's first and last element:
given_letters = ["a", "b", "c", "d", "f"]
first_letter = given_letters.first #=> "a"
last_letter = given_letters.last #=> "f"
and call String#upto and Enumerable#to_a to retrieve an array of all successive letters:
all_letters = first_letter.upto(last_letter).to_a
#=> ["a", "b", "c", "d", "e", "f"]
which can be used to calculate the difference to the original array via Array#-:
all_letters - given_letters
#=> ["e"]

Let
ascii = arr.uniq.map(&:ord)
#=> [97, 98, 99, 100, 102]
sm, lg = ascii.minmax
#=> [97, 102]
If it is known that there is exactly one letter e for which sm < e.ord < lg and e is not an element of arr, we can write the following.
((sm+lg)*(lg-sm+1)/2 - ascii.sum).chr
#=> (597 - 496).chr => 101.chr => "e"
That is because sm..lg represents an arithmetic progression; hence, the sum of its elements equals
(sm+lg)*(lg-sm+1)/2
#=> 597

Related

Caesar Cipher - Ruby

I have to make a function that receives a phrase and encrypts it. The cipher is to each letter in alphabet the encrypted letter is 3 letter ahead.
Example
Alphabet: A B C D E F G ... X Y Z
Ciphered: D E F G H I J ... A B C
If this is my alphabet in Ruby:
a = ['a','b','c','d','e']
I need to map it to:
a = ['c','d','e','a','b']
I've tried iterate twice the array and remove some indexes but I know I'm missing something.
UPDATE--------------------------------------------------------------------
I've managed to solve the six tests where I receive a phrase and have to encrypts as the test require.
Received phrase: prefiro perder a guerra e ganhar a paz
Phrase expected: suhilur#shughu#d#jxhuud#h#jdqkdu#d#sd}
I realize that to cypher the phrase I should change the letters positions 3 positions ahead in the ascii table.
Example: The letter 'a' should be encrypted as 'd', The letter 'z' should be encrypted as '}' and also the 'space' 3 positions ahead in the ascii table is '#'.
Here follows the code I used to solve this:
def cipher(text)
key = 3
cipher_text = text.chars.map {|x| x.ord}
.map {|x| x+key}
cipher_text.map { |x| x.chr }.join
end
def decipher(text)
key = 3
decipher_text = text.chars.map {|x| x.ord}
.map {|x| x-key}
decipher_text.map { |x| x.chr }.join
end
For encryption mentioned in the comments use String.tr method
I have to make a function that receives a phrase and encrypts it. The
cipher is to each letter in alphabet the encrypted letter is 3 letter
ahead.
phrase = "abcd st xyz"
encrypted = phrase.tr("A-Za-z ", "D-ZA-Cd-za-c#")
# => "defg#vw#abc"
Update
Please notice that the letter 'z' (at the end of the phrase) means
'}'
You can map xyz character to {|} explicitly
phrase = "prefiro perder a guerra e ganhar a paz"
encrypted = phrase.tr("A-Wa-wXYZxyz ", "D-WA-Cd-wa-c{|}{|}#")
# => "suhilur#shughu#d#jxhuud#h#jdqkdu#d#sd}"
Not sure I understand your question, but the data looks like you rotate the elements in the array. In Ruby you have a special method for that.
a = %w[a b c d] #=> ["a", "b", "c", "d"]
a.rotate #=> ["b", "c", "d", "a"]
a #=> ["a", "b", "c", "d"]
a.rotate(2) #=> ["c", "d", "a", "b"]
a.rotate(-3) #=> ["b", "c", "d", "a"]
Given an alphabet:
alphabet = ('A'..'Z').to_a
#=> ["A", "B", "C", "D", "E", ..., "V", "W", "X", "Y", "Z"]
You can create the ciphered one by calling rotate:
ciphered = alphabet.rotate(3)
#=> ["D", "E", "F", "G", "H", ..., "Y", "Z", "A", "B", "C"]
And create a mapping from one to the other:
to_cipher = alphabet.zip(ciphered).to_h
#=> {"A"=>"D", "B"=>"E", "C"=>"F", ..., "X"=>"A", "Y"=>"B", "Z"=>"C"}
Now, to encrypt a given string, we have to run each character through that hash:
'HELLO WORLD!'.each_char.map { |char| to_cipher[char] }.join
#=> "KHOORZRUOG"
Well, almost. That also removed the space and exclamation mark. We can fix this by providing a fallback for characters that don't occur in the hash:
'HELLO WORLD!'.each_char.map { |char| to_cipher.fetch(char, char) }.join
#=> "KHOOR ZRUOG!"
Or, with regular expressions using gsub:
'HELLO WORLD!'.gsub(Regexp.union(to_cipher.keys), to_cipher)
#=> "KHOOR ZRUOG!"

Count array with condition

So I have a array of characters and I'd like to display all permutations of a given size meeting a certain condition. For instance, if my array contains 'L', 'E' and 'A' and I choose to display all permutations of size 3 that ends with 'L'. There are two possibilities, ["A", "E", "L"] and ["E", "A", "L"].
My problem is: how can I count the number of possibilities and print all the possibilities within the same each? Here's what I have so far:
count = 0
combination_array.select do |item|
count += 1 if item.last == 'L'
puts "#{item} " if item.last == 'L'
end
It works fine, but I have to write the condition 2 times and also I can't write before displaying all possibilities. I've created a method
def count_occurrences(arr)
counter = 0
arr.each do |item|
counter += 1 if item.last == 'L'
end
counter
end
but I still have to repeat my condition (item.last == 'L'). it doesn't seem very efficient to me.
You could use each_cons (docs) to iterate through each set of 3 items, and count (docs) in block form to have Ruby count for you without constructing a new array:
matches = [["E", "A", "L"], ["A", "E", "L"]]
match_count = data.each_cons(3).count do |set|
if matches.include?(set)
puts set.to_s
return true
end
end
If you really dislike the conditional block, you could technically simplify to a one-liner:
stuff_from_above.count do |set|
matches.include?(set) && !(puts set.to_s)
end
This takes advantage of the fact that puts always evaluates to nil.
And if you're feeling extra lazy, you can also write ["A", "E", "L"] as %w[A E L] or "AEL".chars.
If you specifically want to display and count permutations that end in "L", and the array arr is known to contain exactly one "L", the most efficient method is to simply generate permutations of the array with "L" removed and then tack "L" onto each permutation:
arr = ['B', 'L', 'E', 'A']
str_at_end = 'L'
ar = arr - [str_at_end]
#=> ["B", "E", "A"]
ar.permutation(2).reduce(0) do |count,a|
p a + [str_at_end]
count += 1
end
#=> 6
displaying:
["B", "E", "L"]
["B", "A", "L"]
["E", "B", "L"]
["E", "A", "L"]
["A", "B", "L"]
["A", "E", "L"]
If you want to do something else as well you need to state specifically what that is.
Note that the number of permutations of the elements of an array of size n is simply n! (n factorial), so if you only need the number of permutations with L at the end you could compute that as factorial(arr.size-1), where factorial is a simple method you would need to write.

Print elements of array of arrays of different size in same line in Ruby

Maybe someone could help me with this. I have an array of arrays. The internal arrays have different sizes (from 2 to 4 elements).
letters = [["A", "B"],["C", "D", "F", "G"],["H", "I", "J" ]]
I'm trying to print in a same line each array havins as first column element[0] and element[1] joined, as 2nd column element[0], element[1], element[2] joined as 3rd column element[0], element[1], element[3] joined. Elements 2 and 3 not always exist.
The output I'm trying to get is like this:
AB
CD CDF CDG
HI HIJ
I'm doing in this way but I'm getting this error.
letters.map{|x| puts x[0]+x[1] + "," + x[0]+x[1]+x[2] + "," + x[0]+x[1]+x[3]}
TypeError: no implicit conversion of nil into String
from (irb):1915:in "+"
from (irb):1915:in "block in irb_binding"
from (irb):1915:in "map"
from (irb):1915
from /usr/bin/irb:11:in "<main>"
letters.each do |a,b,*rest|
puts rest.each_with_object([a+b]) { |s,arr| arr << arr.first + s }.join(' ')
end
prints
AB
CD CDF CDG
HI HIJ
The steps are as follows.
Suppose
letters = [["C", "D", "F", "G"],["H", "I", "J" ]]
Then
enum0 = letters.each
#=> #<Enumerator: [["C", "D", "F", "G"], ["H", "I", "J"]]:each>
The first element of this enumerator is generated and passed to the block, and the three block variables are assigned values.
a, b, *rest = enum0.next
#=> ["C", "D", "F", "G"]
a
#=> "C"
b
#=> "D"
rest
#=> ["F", "G"]
Next, we obtain
enum1 = rest.each_with_object([a+b])
#=> rest.each_with_object(["CD"])
#=> #<Enumerator: ["F", "G"]:each_with_object(["CD"])>
The first element of this enumerator is generated and passed to the block, and the block variables are assigned values.
s, arr = enum1.next
#=> ["F", ["CD"]]
s
#=> "F"
arr
#=> ["CD"]
The block calculation is now performed.
arr << arr.first + s
#=> arr << "CD" + "F"
#=> ["CD", "CDF"]
The second and last element of enum1 is generated and passed to the block, and block variables are assigned values and the block is computed.
s, arr = enum1.next
#=> ["G", ["CD", "CDF"]]
arr << arr.first + s
#=> ["CD", "CDF", "CDG"]
When an attempt to generate another element from enum1 we obtain
enum1.next
#StopIteration: iteration reached an end
Ruby handles the exception by breaking out of the block and returning arr. The elements of arr are then joined:
arr.join(' ')
#=> "CD CDF CDG"
and printed.
The second and last element of enum0 is now generated, passed to the block, and the three block variables are assigned values.
a, b, *rest = enum0.next
#=> ["H", "I", "J"]
a
#=> "H"
b
#=> "I"
rest
#=> ["J"]
The remaining calculations are similar.
Some readers may be unfamiliar with the method Enumerable#each_with_object, which is widely used. Read the doc, but note that here it yields the same result as the code written as follows.
letters.each do |a,b,*rest|
arr = [a+b]
rest.each { |s| arr << arr.first + s }
puts arr.join(' ')
end
By using each_with_object we avoid the need for the statement arr = [a+b] and the statement puts arr.join(' '). The functions of those two statements are of course there in the line using each_with_object, but most Ruby users prefer the flow when when chaining each_with_object to join(' '). One other difference is that the value of arr is confined to each_with_object's block, which is good programming practice.
Looks like you want to join the first two letters, then take the cartesian product with the remaining.
letters.each do |arr|
first = arr.take(2).join
rest = arr.drop(2)
puts [first, [first].product(rest).map(&:join)].join(" ")
end
This provides the exact output you specified.
Just out of curiosity, Enumerable#map-only solution.
letters = [["A", "B"],["C", "D", "F", "G"],["H", "I", "J" ]]
letters.map do |f, s, *rest|
rest.unshift(nil).map { |l| [f, s, l].join }.join(' ')
end.each(&method(:puts))
#⇒ AB
# CD CDF CDG
# HI HIJ

ruby remove same value multiple keys in hash

from following hash
hash ={"a"=>100,"b"=>200,"c"=>100,"d"=>120,"e" => 400, "f"=>430, "g"=>500}
I want to remove all the pairs ("key", "value") having either same "value" or have diff of 50(of "value").
example, a=>100 and c => 100, should be removed as they have same "value". And d=>120 should also be removed along with as the difference between 100 and 120 is 20. 400 and 430 should also be removed as the difference is 30.
I should have only
hash["b"=>200,"g"=>500]
Above just an example, in reality, I have hash of 33,000 keys.
A pair of a hash's key/value pairs, k1=>v1 and k2=>v2, are both to be deleted if (v1-v2).abs <= 50. This includes pairs for which v1 == v2, so we need not consider the latter separately. I would do this by first constructing an array of keys to keep, then create a hash comprised of the corresponding key/value pairs from the original hash.
Code
keys_to_keep = hash.keys -
hash.sort_by { |_,v| v }
.each_cons(2)
.each_with_object([]) {
|((k1,v1),(k2,v2)),a| a << k1 << k2 if (v1-v2).abs <= 50 }
keys_to_keep.zip(hash.values_at(*keys_to_keep)).to_h
Explanation
hash = {"a"=>100,"b"=>200,"c"=>100,"d"=>120}
Sort by hash values:
b = hash.sort_by { |_,v| v }
#=> [["a", 100], ["c", 100], ["d", 120], ["b", 200]]
Next, use Enumerable#each_cons to construct an array of all adjacent pairs of elements of b:
c = b.each_cons(2)
#=> #<Enumerator:
# [["a", 100], ["c", 100], ["d", 120], ["b", 200]]:each_cons(2)>
To view the contents of this enumerator:
c.to_a
#=> [[["a", 100], ["c", 100]],
# [["c", 100], ["d", 120]],
# [["d", 120], ["b", 200]]]
Now build an array consisting of keys to be deleted (duplicates OK)
d = c.each_with_object([]) {
|((k1,v1),(k2,v2)),a| a << k1 << k2 if (v1-v2).abs <= 50 }
#=> ["a", "c", "c", "d"]
To compute d, consider the first value passed to the block by the enumerator c:
k1 => "a"
v1 => 100
k2 => "c"
v2 => 100
Since
(100 - 100).abs <= 50
keys k1 and k2 are added to the array of keys to be deleted (block variable a). The next value passed to the block is:
k1 => "c"
v1 => 100
k2 => "d"
v2 => 120
Since
(100 - 120).abs <= 50
the keys "c" and "d" are also added to a. The third value does not add any keys to a since
(120 - 200).abs > 50
Now construct an array of keys to keep by using set difference:
e = hash.keys
#=> ["a", "b", "c", "d"]
keys_to_keep = e - d
#=> ["b"]
Pull out the values for the keys to keep, using Hash#values_at:
f = hash.values_at(*keys_to_keep)
#=> [200]
Construct an array of key/value pairs for keys to keep:
g = keys_to_keep.zip(f)
#=> [["b", 200]]
Convert to a hash.
g.to_h # Ruby v.2.0+
#=> {"b"=>200}
or
Hash[g]
#=> {"b"=>200}
Try this:
multiple_values = hash.group_by { |k, v| v }.select { |v, i| i.length > 1 }.map { |v, i| v }
hash.delete_if { |k, v| multiple_values.any? { |i| v < i + 50 && v > i - 50 } }
The first line builds a histogram for all the values (groups entries by value), and filters out all the values which have only one entry.
This gives us a list of all the values which have more than one key associated with them.
The second pass removes all keys whose values are close to one of these by less than 50.

hash of Array gives incorrect size results - Ruby

I am trying to insert a List in Hash.. However, hash[key].size is giving me invalid results.
p = Hash.new
p = {"a" => ["b","e"]}
puts p["a"].size #prints 2 ----This is the Problem
p["a"] << ["d", "f"]
puts p["a"].size #prints 3
puts p["a"][1] #prints e
puts p["a"][2] #prints df
How, adding more lists increment the size only by one (which is correct). Is there any way to properly initialize the hash -to not increase the size to 2.
Edited to add: Your comments indicate that you want for element 'a' to be an array of arrays. Here it is:
h = Hash.new
h = {"a" => [["b","e"]]}
p h # => {"a"=>[["b", "e"]]}
h["a"] << ["d", "f"]
p h # => {"a"=>[["b", "e"], ["d", "f"]]}
When diagnosing a problem, prefer p to puts. puts can hide details that are important. Let's add a few calls to p and see what we find out. Oh, and I'll change the name of the hash from "p" to "h". Otherwise there's just too many "p's" around.
h = Hash.new
The above line is unnecessary. The next line assigns an array to "h", overwriting this assignment.
h = {"a" => ["b","e"]}
p h # => {"a"=>["b", "e"]}
p h["a"].size # 2
Everything is exactly as it should be, even h["a"].size returning 2. why?
p h["a"] # => ["b", "e"]
Because h["a"] is an array with two elements.
h["a"] << ["d", "f"]
p h # => {"a"=>["b", "e", ["d", "f"]]}
Do you see what happened? << appends a single element to the end of an array, and that single element is the array ["d", "f"]. And that's why:
p h["a"].size # => 3
Because there are indeed three elements in the array: the strings "b" and "e", and the array ["d", "f"].
If you meant to append the elements "d" and "f" to the array, then do it with +=:
h = {"a" => ["b","e"]}
h["a"] += ["d", "f"]
p h # => {"a"=>["b", "e", "d", "f"]}

Resources