How to find keys in hash by number of values? (Ruby) [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I want to search through a hash for keys with only one value, and divide that value by 2. How do I go about this?
Example
hash = { a => [4], b => [2, 4, 5], c => [3, 5] }
Result sought
hash = { a => [2], b => [2, 4, 5], c => [3, 5] }

hash = {:a=>[4], :b=>[2, 4, 5], :c=>[3, 5]}
You can use transform_values:
hash.transform_values { |v| v.one? ? [v[0]/2.0] : v }
#=> {:a=>[2.0], :b=>[2, 4, 5], :c=>[3, 5]}
Or map
hash.map { |k,v| v.one? ? [k,[v[0]/2.0]] : [k,v] }.to_h
#=> {:a=>[2.0], :b=>[2, 4, 5], :c=>[3, 5]}

This should do the trick, just iterate over each key/value pair and check the length of the values, if it only has 1 item, set the key in the hash to be equal to half the original value.
hash = { a: [4], b: [2, 4, 5], c: [3, 5] }
# => {:a=>[4], :b=>[2, 4, 5], :c=>[3, 5]}
hash.each do |key, values|
if 1 == values.length
hash[key] = [values.first / 2]
end
end
# => {:a=>[2], :b=>[2, 4, 5], :c=>[3, 5]}

Related

Finding paths in an adjacency list [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
What is the optimal algorithm to find all the paths between 2 nodes of an adjacency list
Example input:
source = 1
destination = 5
list = {1: [2], 2: [4], 3: [4, 5], 4: [5]}
def paths(adj, st, en)
return [] unless adj.key?(st)
adj[st].each_with_object([]) do |nxt,arr|
nxt == en ? arr << [st, en] :
paths(adj, nxt, en).each { |a| arr << [st, *a] }
end
end
adj = { 1=>[2,3], 2=>[4,7], 3=>[4,8], 4=>[5,6], 5=>[7], 6=>[7] }
Note that I added an isolated node 8.
paths(adj, 1, 7)
#=> [[1, 2, 4, 5, 7],
# [1, 2, 4, 6, 7],
# [1, 2, 7],
# [1, 3, 4, 5, 7],
# [1, 3, 4, 6, 7]]

How to shift the values in a hash to another key

I am having trouble figuring the best approach to shift some values to another key. Every value most go to the next key, and the last key's values need to be completely removed. For example
hash1 = { a: [1, 2, 3], b: [4, 5, 6], c: [7, 8, 9] }
desired_hash = hash1.some_method
desired_hash === { a: [], b: [1, 2, 3], c: [4, 5, 6] }
My thought is to rename the hash keys but was not sure if this was the best approach.
hash1 = { a: [1, 2, 3], b: [4, 5, 6], c: [7, 8, 9] }
keys = hash1.keys
=> [:a, :b, :c]
values = hash1.values
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
keys.zip(values.unshift([])).to_h
=> {:a=>[], :b=>[1, 2, 3], :c=>[4, 5, 6]}
pv = []
hash1.each_with_object({}) do |(k,v),h|
h[k] = pv
pv = v
end
#=> {:a=>[], :b=>[1, 2, 3], :c=>[4, 5, 6]}
Assuming the hash keys are "in correct order" already.
You can try this:
def shift(input)
output = {}
keys = input.keys
0.upto(keys.size - 1) do |index|
current = keys[index]
if index > 0
previous = keys[index - 1]
output[current] = input[previous]
else
output[current] = []
end
end
output
end
input = { a: [1, 2, 3], b: [4, 5, 6], c: [7, 8, 9] }
p shift(input)
it's not very elegant, there is probably a much nicer solution but it's a starting point.

Operate on array elements without changing index

I'm trying to operate on certain elements of an array while referencing their index in the block. Operating on the whole array is easy
arr = [1, 2, 3, 4, 5, 6, 7, 8]
arr.each_with_index { |num, index| puts "#{num}, "#{index}" }
But what if I want to work just with elements 4, 6 to return
4, 3
6, 5
I can create a new array composed of certain elements of the original and run the block on that, but then the index changes.
How can I select the elements and their index?
Just put a condition on it:
indice = [3, 5]
arr.each_with_index do
|num, index| puts "#{num}, #{index}" if indice.include?(index)
end
This is another style:
indice = [3, 5]
arr.each_with_index do
|num, index|
next unless indice.include?(index)
puts "#{num}, #{index}"
end
I cannot tell from the question whether you are given values in the array and want to obtain their indices, or vice-versa. I therefore will suggest one method for each task. I will use this array for examples:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
Values to Indices
If you are given values:
vals = [4, 6]
you can retrieve the number-index pairs like this:
vals.map { |num| [num, arr.index(num)] }
#=> [[4, 3], [6, 5]]
or print them directly:
vals.each { |num| puts "#{num}, #{arr.index(num)}" }
# 4, 3
# 6, 5
#=> [4, 6]
If an element of vals is not present in arr:
vals = [4, 99]
vals.map { |num| [num, arr.index(num)] }
#=> [[4, 3], [99, nil]]
Indices to Values
If you are given indices:
indices = [3, 5]
you can retrieve the index-value pairs like this:
indices.zip(arr.values_at(*indices))
#=> [[3, 4], [5, 6]]
and then print in whatever format you like.
If an index is out-of-range, nil will be returned:
indices.zip(arr.values_at(*[3, 99]))
#=> [[3, 4], [5, nil]]

How to access a nested element, passing array with coordinates

Is there any short way to access an element of a nested array, passing the array with coordinates? I mean something like:
matrix = [[1,2,3,4],[5,6,7,8]]
array = [1,1]
matrix [array]
# => 6
I just wonder if there is a shorter version than:
matrix [array[0]][array[1]]
I believe you want to use the Matrix class:
require 'matrix'
arr = [[1,2,3,4],[5,6,7,8]]
matrix = Matrix[*arr] #=> Matrix[[1, 2, 3, 4], [5, 6, 7, 8]]
matrix[1,1] #=> 6
matrix.row(1) #=> Vector[5, 6, 7, 8]
c = matrix.column(1) #=> Vector[2, 6]
c.to_a #=> [2, 6]
m = matrix.transpose #=> Matrix[[1, 5], [2, 6], [3, 7], [4, 8]]
m.to_a #=> [[1, 5], [2, 6], [3, 7], [4, 8]]
array.inject(matrix, :fetch)
# => 6
matrix[1][1]
should equal 6. matrix[1] is the 2nd array, matrix[1][1] is the second element in that array.

Indexing elements in hash

Lets supose that I have a hash:
class MyHash
H = { 1 => [1,2,3,4,5], 2 => [2,7,8,9,10] }
def self.get(id)
# code
end
end
How is the implementation for that method so that I can access the data this way?
element = MyHash.get 1
# => [1,2]
element = MyHash.get 6
# => [2,7]
element = MyHash.get 4
# => [1,5]
element = MyHash.get 5
# => [2,2]
I can write the method "manually" but maybe there is a simpler "rubyist" method to do that
You could do this:
H = { 1 => [1,2,3,4,5], 2 => [6,7,8,9,10] }
HINV = H.flat_map { |k,v| [k].product(v) }
.map.with_index { |(k,v),i| [i,[k,v]] }
.to_h
#=> {0=>[1, 1], 1=>[1, 2], 2=>[1, 3], 3=>[1, 4], 4=>[1, 5],
# 5=>[2, 6], 6=>[2, 7], 7=>[2, 8], 8=>[2, 9], 9=>[2, 10]}
class MyHash
def self.get(id)
HINV[id]
end
end
MyHash.get(1) #=> [1, 2]
MyHash.get(6) #=> [2, 7]
MyHash.get(4) #=> [1, 5]
There is, however, no need for the class MyHash:
HINV[1] #=> [1, 2]
HINV[6] #=> [2, 7]
HINV[4] #=> [1, 5]
If you don't wish the hash to be a constant:
def invert_hash_by_values_index(h)
Hash[h.flat_map { |k,v| [k].product(v) }
.map.with_index { |(k,v),i| [i,[k,v]] }]
end
h = { 1 => [1,2,3,4,5], 2 => [6,7,8,9,10] }
hinv = invert_hash_by_values_index(h)
#=> {0=>[1, 1], 1=>[1, 2], 2=>[1, 3], 3=>[1, 4], 4=>[1, 5],
# 5=>[2, 6], 6=>[2, 7], 7=>[2, 8], 8=>[2, 9], 9=>[2, 10]}
hinv[1] #=> [1, 0]
hinv[6] #=> [2, 0]
hinv[4] #=> [1, 3]
Here I've used the class method Hash::[], rather than instance method Array#to_h, the latter having been added in Ruby 2.0.

Resources