Select filed from Array of Hashes in Ruby - arrays

So i have this Array of Hashes
{"id"=>50823, "code"=>"1PLAK", "name"=>"Eselente", "order"=>1}
{"id"=>74327, "code"=>"1MAGP", "name"=>"Mango", "order"=>2}
{"id"=>50366, "code"=>"1ANGC", "name"=>"Tabnie", "order"=>3}
{"id"=>76274, "code"=>"1FABD", "name"=>"Slamtab", "order"=>4}
And i want to select the field order (just one field at the same time) for comparing afterwards.
What's the correct way to do it?
Thanks!

When you only want to extract the values of the orders then I would do this:
array = [
{"id"=>50823, "code"=>"1PLAK", "name"=>"Eselente", "order"=>1},
{"id"=>74327, "code"=>"1MAGP", "name"=>"Mango", "order"=>2},
{"id"=>50366, "code"=>"1ANGC", "name"=>"Tabnie", "order"=>3},
{"id"=>76274, "code"=>"1FABD", "name"=>"Slamtab", "order"=>4},
]
array.map { |hash| hash["order"] }
#=> [1, 2, 3, 4]
When you are only interested in the very first value (1 like you wrote in the comments above) then you can do:
array.first["order"] # or array[0]["order"]
#=> 1

Related

Sort an array of arrays by the number of same occurencies in Ruby

This question is different from this one.
I have an array of arrays of AR items looking something like:
[[1,2,3], [4,5,6], [7,8,9], [7,8,9], [1,2,3], [7,8,9]]
I would like to sort it by number of same occurences of the second array:
[[7,8,9], [1,2,3], [4,5,6]]
My real data are more complexes, looking something like:
raw_data = {}
raw_data[:grapers] = []
suggested_data = {}
suggested_data[:grapers] = []
varietals = []
similar_vintage.varietals.each do |varietal|
# sub_array
varietals << Graper.new(:name => varietal.grape.name, :grape_id => varietal.grape_id, :percent => varietal.percent)
end
raw_data[:grapers] << varietals
So, I want to sort raw_data[:grapers] by the max occurrencies of each varietals array comparing this value: grape_id inside them.
When I need to sort a classical array of data by max occurencies I do that:
grapers_with_frequency = raw_data[:grapers].inject(Hash.new(0)) { |h,v| h[v] += 1; h }
suggested_data[:grapers] << raw_data[:grapers].max_by { |v| grapers_with_frequency[v] }
This code doesn't work cos there are sub arrays there, including AR models that I need to analyze.
Possible solution:
array.group_by(&:itself) # grouping
.sort_by {|k, v| -v.size } # sorting
.map(&:first) # optional step, depends on your real data
#=> [[7, 8, 9], [1, 2, 3], [4, 5, 6]]
I recommend you take a look at the Ruby documentation for the sort_by method. It allows you to sort an array using anything associated with the elements, rather than the values of the elements.
my_array.sort_by { |elem| -my_array.count(elem) }.uniq
=> [[7, 8, 9], [1, 2, 3], [4, 5, 6]]
This example sorts by the count of each element in the original array. This is preceded with a minus so that the elements with the highest count are first. The uniq is to only have one instance of each element in the final result.
You can include anything you like in the sort_by block.
As Ilya has pointed out, having my_array.count(elem) in each iteration will be costlier than using group_by beforehand. This may or may not be an issue for you.
arr = [[1,2,3], [4,5,6], [7,8,9], [7,8,9], [1,2,3], [7,8,9]]
arr.each_with_object(Hash.new(0)) { |a,h| h[a] += 1 }.
sort_by(&:last).
reverse.
map(&:first)
#=> [[7.8.9]. [1,2,3], [4,5,6]]
This uses the form of Hash::new that takes an argument (here 0) that is the hash's default value.

collect all elements and indices of an array in two separate arrays in Ruby

Suppose I have an array array = [1,2,3,4,5]
I want to collect all the elements and indices of the array in 2 separate arrays like
[[1,2,3,4,5], [0,1,2,3,4]]
How do I do this using a single Ruby collect statement?
I am trying to do it using this code
array.each_with_index.collect do |v,k|
# code
end
What should go in the code section to get the desired output?
Or even simpler:
[array, array.each_index.to_a]
I like the first answer that was posted a while ago. Don't know why the guy deleted it.
array.each_with_index.collect { |value, index| [value,index] }.transpose
Actually I am using an custom vector class on which I am calling the each_with_index method.
Here's one simple way:
array = [1,2,3,4,5]
indexes = *array.size.times
p [ array, indexes ]
# => [[1, 2, 3, 4, 5], [0, 1, 2, 3, 4]]
See it on repl.it: https://repl.it/FmWg

How to find the key of a hash whose value has the most elements

I'm using Ruby 2.4.
I have a hash whose key is a number and whose value is an array of elements. How do I find the key in the hash with the value that has the most elements? I know that if my value were a single number I could do this:
my_hash.max_by { |k, v| v }
But since the value is an array, I'm not sure how to tell the above to use the number of elements in the array as what should be maxed.
max_by is the correct method :
my_hash = { a: [1, 2], b: [1, 2, 3], c: [5] }
key, longest_array = my_hash.max_by{ |k, array| array.size }
p key
#=> :b
p longest_array
#=> [1, 2, 3]
You just need to specify on which object the comparison should be. In this case, the size of the array value.
You might need to add some checks first : this will only work if all the hash values respond to :size.
You can do it like this:
my_hash.map {|k, v| [k, v.count]}.max_by {|k, v| v}.first
The first map will return an array of two elements arrays. For each of them, the first element is the key and the second is the number of elements of the corresponding array. Then it uses max_by to return the two element array with the maximum number of elements. Finally, the first method returns the key.
I'm not sure if I understood your question correctly, but I'm assuming you have something like this:
my_hash = {1=>[2, 1, 3, 4], 2=>[1, 2], 3=>[1, 4, 6]}
If that's the case, you can get the key for the largest array like this:
my_hash.max_by{|k,v| v.count}.first

Find the index by current sort order of an array in ruby

If there is an array
array A = ["a","b","c","d"] #Index is [0,1,2,3]
And it's sorted to.
array A = ["d","c","b","a"]
I need an array that returns me the updated index based on the sorted order
[3,2,1,0]
I'm trying to find a solution to this ruby
UPDATE to the question
If a is sorted to
array A = ["d","b","c","a"] #not a pure reverse
Then the returned index array should be
[3,1,2,0]
You need to create a mapping table that preserves the original order, then use that order to un-map the re-ordered version:
orig = %w[ a b c d ]
orig_order = orig.each_with_index.to_h
revised = %w[ d c b a ]
revised.map { |e| orig_order[e] }
# => [3, 2, 1, 0]
So long as your elements are unique this will be able to track any shift in order.
Here is one way to do this:
original_array = ["a","b","c","d"]
jumbled_array = original_array.shuffle
jumbled_array.map {|i| original_array.index(i)}
#=> [1, 3, 0, 2]
Note:
In this sample, output will change for every run as we are using shuffle to demonstrate the solution.
The solution will work only as long as array has no duplicate values.
If you do wish to solution to work with arrays with duplicate values, then, one possibility is to look at object_id of array members while figuring out the index.
jumbled_array.map {|i| original_array.map(&:object_id).index(i.object_id)}
This solution will work as long as jumbled_array contains element from original_array and no elements were recreated using dup or something that results in change in object_id values
You can use the map and index methods.
arr = ["a","b","c","d"]
sort_arr = ["d","c","b","a"]
sort_arr.map{|s| arr.index(s)}
# => [3, 2, 1, 0]

How to change only elements of one array that are missing in another in Ruby?

If I have 2 arrays, for example a = [1, 2, 3, 4, 5] and b = [4, 7, 9, 1]
and I want to use a method to change elements of the first one. For example
a.map {|x| x.to_s}
but I don't want to change elements that are the same as in the array b.
In this case my desire result would be
a = [1, "2", "3", 4, "5"]
1 and 4 are still integers, because the array b has this elements.
So how can I implement this task?
arrays and methods are used just for example to explain what I mean.
you can achieve this with a simple ternary operator inside your map block to either add the respective element as is or as a string depending on whether the second array contains an element with that value:
a.map { |x| (b.include? x) ? x : x.to_s }
a.map!{|e| b.include?(e) ? e : e.to_s}

Resources