I need to have a Hash in which keys are represented by arrays with chars.
But when i have arrays like these:
a = %w(a b c), b = %w(d e f), c = %w(g h i)
and i create a new Hash and try to give it values, my results are strange, i expect something similar to this:
H = { ["a", "b", "c"] => 1, ["d", "e", "f"] => 2 }
but i get something like this:
{"[\"a\", \"b\", \"c\"]"=>1}
The way i create this hash is simple:
H = {}
H["#{array_name}"]
Is this normal behaviour? If so how can i make these keys normal arrays of chars?
a,b,c are local variables. They are not array names. They are holding the references of 3 different Array instances. So do as below :
a = %w(a b c)
b = %w(d e f)
c = %w(g h i)
H = {}
H[a] = 1
H[b] = 2
H[c] = 3
H # => {["a", "b", "c"]=>1, ["d", "e", "f"]=>2, ["g", "h", "i"]=>3}
One Rubyish way :
a = %w(a b c), %w(d e f), %w(g h i)
Hash[a.zip([1,2,3])]
# => {["a", "b", "c"]=>1, ["d", "e", "f"]=>2, ["g", "h", "i"]=>3}
Related
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!"
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
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.
So this is hurting my head, I am not very good with programming obviously. I have,
LetterArray = [a,b,c,d,e,f,g]
NumArray = [1,2,3,4,5,6,7,8,9,10]
ListOfLetters = []
and I want to take an element from NumArray and, starting on LetterArray[0], go up var x amount of times in LetterArray, and add that element (say var y to the array. Then starting on y go up the next number in NumArray, and so on. Then print the ListOfLetters to console.
My goal is for the output to be like this: [a, c, f, c, a, f, e, e, f, a].
I am drawing a blank on how to go about this in code.
Something like this (if I get your requirements right of course)?
letter_array = %w[a b c d e f g]
number_array = [1,2,3,4,5,6,7,8,9,10]
list_of_letters = []
number_array.inject(0) do |offset, delta|
list_of_letters << letter_array[offset]
(offset + delta) % letter_array.size
end
p list_of_letters #=> ["a", "b", "d", "g", "d", "b", "a", "a", "b", "d"]
Either I don't understand your problem description, or the example output you showed is wrong from a certain point onwards. Anyway, maybe this gets you started:
letter_array = [*?a..?g]
number_array = *1..10
list_of_letters = []
number_array.inject(0) do |s, n|
i = s + n
list_of_letters << letter_array[i % letter_array.size - 1]
i
end
This produces the output ["a", "c", "f", "c", "a", "g", "g", "a", "c", "f"].
Alternatively you can also first create the indices and then use them (this doesn't require a pre-initialized list_of_letters):
indices = number_array.inject([]) { |a, n| a << (a.last || 0) + n ; a})
list_of_letters = indices.map { |i| letter_array[i%letter_array.size-1] }
ar = ('a'..'g').to_a.cycle #keeps on cycling
res = []
p 10.times.map do |n|
n.times{ar.next} #cycle one time too short (the first time n is 0)
res << ar.next #cycle once more and store
end
p res #=>["a", "c", "f", "c", "a", "g", "g", "a", "c", "f"]
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"]}