I have an array which contains man value I am trying to use map method using another array and I want to select few values from first array:
My first array is:
data = [
"Agriculture, forestry and fishing",
"Crops",
"Livestock",
"Forestry and logging",
"Fishing and aquaculture",
"Mining and quarrying",
]
And my second array is:
b = [
{
id: 1,
Sector: "Agriculture, forestry and fishing",
2011-12: 25.7,
2012-13: 27,
2013-14: 22.8,
2014-15: 22,
2015-16: 21.1,
2016-17: 20.6,
created_at: "2018-08-23T06:48:27.000Z",
updated_at: "2018-08-23T06:48:27.000Z"
},
{
id: 2,
Sector: "Crops",
2011-12: 17.6,
2012-13: 18.9,
2013-14: 14.2,
2014-15: 13.1,
2015-16: 12.3,
2016-17: 12.1,
created_at: "2018-08-23T06:48:27.000Z",
updated_at: "2018-08-23T06:48:27.000Z"
}
....
]
My full data you can see it here: My second data
I am using this code:
#hash_data = data.map{ |vegetable|
dataset = vegetable.to_s.gsub("_"," ")
{
type: views,
legendText: dataset,
showInLegend: true,
dataPoints: b.map { |value|
{ y: value[_year], label: value[:Sector] }
}
}
}
How can I just select values from b array and show only those values which are in my data array.
Using Regexp.union passing your data attributes returns a Regexp
/Agriculture,\ forestry\ and\ fishing|Crops|Livestock|Forestry\ and\ logging|Fishing\ and\ aquaculture|Mining\ and\ quarrying/
that you can use to check every Section key within the elements on b:
b = [...]
data = [
"Agriculture, forestry and fishing",
"Crops",
"Livestock",
"Forestry and logging",
"Fishing and aquaculture",
"Mining and quarrying",
]
regex = Regexp.union(data)
result = b.select { |hash| hash[:Sector] =~ regex }
p result
# [{:id=>1, :Sector=>"Agriculture, forestry and fishing", :"2011-12"=>25.7, :"2012-13"=>27, :"2013-14"=>22.8, :"2014-15"=>22, :"2015-16"=>21.1, :"2016-17"=>20.6, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>2, :Sector=>"Crops", :"2011-12"=>17.6, :"2012-13"=>18.9, :"2013-14"=>14.2, :"2014-15"=>13.1, :"2015-16"=>12.3, :"2016-17"=>12.1, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, ...]
p result.map { |hash| hash[:Sector] }.sort
# ["Agriculture, forestry and fishing", "Crops", "Fishing and aquaculture", "Forestry and logging", "Livestock", "Mining and quarrying"]
Notice this is working with each value on b as:
{
id: 1,
Sector: "Agriculture, forestry and fishing",
"2011-12": 25.7,
"2012-13": 27,
"2013-14": 22.8,
"2014-15": 22,
"2015-16": 21.1,
"2016-17": 20.6,
created_at: "2018-08-23T06:48:27.000Z",
updated_at: "2018-08-23T06:48:27.000Z"
}
you can try without Regexp:
result = b.select{|e| data.include?(e[:Sector])}
p result
#=> [{:id=>1, :Sector=>"Agriculture, forestry and fishing", :"2011-12"=>25.7, :"2012-13"=>27, :"2013-14"=>22.8, :"2014-15"=>22, :"2015-16"=>21.1, :"2016-17"=>20.6, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>2, :Sector=>"Crops", :"2011-12"=>17.6, :"2012-13"=>18.9, :"2013-14"=>14.2, :"2014-15"=>13.1, :"2015-16"=>12.3, :"2016-17"=>12.1, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>3, :Sector=>"Livestock", :"2011-12"=>5, :"2012-13"=>5, :"2013-14"=>5.4, :"2014-15"=>5.7, :"2015-16"=>5.6, :"2016-17"=>5.5, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>4, :Sector=>"Forestry and logging", :"2011-12"=>1.7, :"2012-13"=>1.7, :"2013-14"=>1.7, :"2014-15"=>1.6, :"2015-16"=>1.5, :"2016-17"=>1.4, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>5, :Sector=>"Fishing and aquaculture", :"2011-12"=>1.3, :"2012-13"=>1.5, :"2013-14"=>1.6, :"2014-15"=>1.7, :"2015-16"=>1.7, :"2016-17"=>1.5, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}, {:id=>6, :Sector=>"Mining and quarrying", :"2011-12"=>0.1, :"2012-13"=>0.1, :"2013-14"=>0.5, :"2014-15"=>0.2, :"2015-16"=>0.6, :"2016-17"=>0.5, :created_at=>"2018-08-23T06:48:27.000Z", :updated_at=>"2018-08-23T06:48:27.000Z"}]
Related
I was looking around for a clean way to do this and I found some workarounds but did not find anything like the slice (some people recommended to use a gem but I think is not needed for this operations, pls correct me if I am wrong), so I found myself with a hash that contains a bunch of hashes and I wanted a way to perform the Slice operation over this hash and get also the key/value pairs from nested hashes, so the question:
Is there something like deep_slice in ruby?
Example:
input: a = {b: 45, c: {d: 55, e: { f: 12}}, g: {z: 90}}, keys = [:b, :f, :z]
expected output: {:b=>45, :f=>12, :z=>90}
Thx in advance! 👍
After looking around for a while I decided to implement this myself, this is how I fix it:
a = {b: 45, c: {d: 55, e: { f: 12}}, g: {z: 90}}
keys = [:b, :f, :z]
def custom_deep_slice(a:, keys:)
result = a.slice(*keys)
a.keys.each do |k|
if a[k].class == Hash
result.merge! custom_deep_slice(a: a[k], keys: keys)
end
end
result
end
c_deep_slice = custom_deep_slice(a: a, keys: keys)
p c_deep_slice
The code above is a classic DFS, which takes advantage of the merge! provided by the hash class.
You can test the code above here
require 'set'
def recurse(h, keys)
h.each_with_object([]) do |(k,v),arr|
if keys.include?(k)
arr << [k,v]
elsif v.is_a?(Hash)
arr.concat(recurse(v,keys))
end
end
end
hash = { b: 45, c: { d: 55, e: { f: 12 } }, g: { b: 21, z: 90 } }
keys = [:b, :f, :z]
arr = recurse(hash, keys.to_set)
#=> [[:b, 45], [:f, 12], [:b, 21], [:z, 90]]
Notice that hash differs slightly from the example hash given in the question. I added a second nested key :b to illustrate the problem of returning a hash rather than an array of key-value pairs. Were we to convert arr to a hash the pair [:b, 45] would be discarded:
arr.to_h
#=> {:b=>21, :f=>12, :z=>90}
If desired, however, one could write:
arr.each_with_object({}) { |(k,v),h| (h[k] ||= []) << v }
#=> {:b=>[45, 21], :f=>[12], :z=>[90]}
I converted keys from an array to a set merely to speed lookups (keys.include?(k)).
A slightly modified approach could be used if the hash contained nested arrays of hashes as well as nested hashes.
My version
maybe it should help
def deep_slice( obj, *args )
deep_arg = {}
slice_args = []
args.each do |arg|
if arg.is_a? Hash
arg.each do |hash|
key, value = hash
if obj[key].is_a? Hash
deep_arg[key] = deep_slice( obj[key], *value )
elsif obj[key].is_a? Array
deep_arg[key] = obj[key].map{ |arr_el| deep_slice( arr_el, *value) }
end
end
elsif arg.is_a? Symbol
slice_args << arg
end
end
obj.slice(*slice_args).merge(deep_arg)
end
Object to slice
obj = {
"id": 135,
"kind": "transfer",
"customer": {
"id": 1,
"name": "Admin",
},
"array": [
{
"id": 123,
"name": "TEST",
"more_deep": {
"prop": "first",
"prop2": "second"
}
},
{
"id": 222,
"name": "2222"
}
]
}
Schema to slice
deep_slice(
obj,
:id,
customer: [
:name
],
array: [
:name,
more_deep: [
:prop2
]
]
)
Result
{
:id=>135,
:customer=>{
:name=>"Admin"
},
:array=>[
{
:name=>"TEST",
:more_deep=>{
:prop2=>"second"
}
},
{
:name=>"2222"
}
]
}
I have parsed the .csv file and received the following headers:
"Date":"Start" "Date":"Due" "Amount":"Total" "Amount":"Left"
There are values for each. I need to map it to hash dynamically in the following way:
{date => {start: value, due: value}, amount => {total: value, left: value}}
Please, could you suggest a way. I've tried to use it as an array like:
[["Date", "Start"], ["Date", "Due"], ["Amount", "Total"], ["Amount", "Left"]]
and then
.each_slice(2)
but after that I got stuck. Thanks in advance
you can try something like:
rows.map do |row|
{
date: { start: row[1], end: row[3] },
amount: { total: row[4], left: row[6] }
}
end
Given:
headers = [["Date", "Start"], ["Date", "Due"], ["Amount", "Total"], ["Amount", "Left"]]
values= [1, 2, 3, 4]
Hash[headers.zip(values)].each_with_object({}) do |(keys, value), memo|
pk = keys.first.downcase.to_sym
memo[pk] ||= {}
memo[pk][keys.last.downcase.to_sym] = value
end
Output:
=> {:date=>{:start=>1, :due=>2}, :amount=>{:total=>3, :left=>4}}
I need the index of an array in a multidimensional array if it contains a unique string.
array:
[
{:id=>5, :name=>"Leaf Green", :hex_value=>"047115"},
{:id=>15, :name=>"Lemon Yellow", :hex_value=>"FFF600"},
{:id=>16, :name=>"Navy", :hex_value=>"285974"}
]
If hex_value of 'FFF600' exists, return the arrays position, which in this case would be 1.
This is where I am at, but it's returning [].
index = array.each_index.select{|i| array[i] == '#FFF600'}
That's returning nil, because there's no element i (index) in the array with value #FFF600 (nor FFF600), you need to access to the hex_value key value:
p [
{:id=>5, :name=>"Leaf Green", :hex_value=>"047115"},
{:id=>15, :name=>"Lemon Yellow", :hex_value=>"FFF600"},
{:id=>16, :name=>"Navy", :hex_value=>"285974"}
].yield_self { |this| this.each_index.select { |index| this[index][:hex_value] == 'FFF600' } }
# [1]
Giving you [1], because of using select, if you want just the first occurrence, you can use find instead.
I'm using yield_self there, to avoid assigning the array to a variable. Which is equivalent to:
array = [
{:id=>5, :name=>"Leaf Green", :hex_value=>"047115"},
{:id=>15, :name=>"Lemon Yellow", :hex_value=>"FFF600"},
{:id=>16, :name=>"Navy", :hex_value=>"285974"}
]
p array.each_index.select { |index| array[index][:hex_value] == 'FFF600' }
# [1]
Being Ruby, you can use the method for that: Enumerable#find_index
p [
{:id=>5, :name=>"Leaf Green", :hex_value=>"047115"},
{:id=>15, :name=>"Lemon Yellow", :hex_value=>"FFF600"},
{:id=>16, :name=>"Navy", :hex_value=>"285974"}
].find_index { |hash| hash[:hex_value] == 'FFF600' }
# 1
I have a rails model object as shown below
[#<Object id: 876, input_type: 4, require_level: true>,#<Object id: 877, input_type: 4, require_level: true>, #<Object id: 878, input_type: 2, require_level: true>]
Input_types is a hash as shown below
input_types = {"w"=>1, "x"=>2, "y"=>3, "z"=>4}
I would like to get output as follows based on the input_type attribute replacement
[#<Object id: 876, input_type: 4, require_level: true>,#<Object id: 877, input_type: 4, require_level: true>, #<Object id: 878, input_type: 2, require_level: true>]
I have the following code:
objects.each do |object|
replacement_key = input_types.key(object.input_type)
object.attributes["input_type"] = replacement_key
end
This does not produce any result and return the object as it is in the initial stage
Try this one
new_objects = objects.map do |object|
replacement_key = input_types.key(object.input_type)
object.input_type = replacement_key
object
end.as_json
This works out. Any better ways without json?
objects = objects.as_json
objects.each do |object|
replacement_key = input_types.key(object["input_type"])
object["input_type"] = replacement_key
end
I have a ruby array that looks something like this:
my_array = ['mushroom', 'beef', 'fish', 'chicken', 'tofu', 'lamb']
I want to sort the array so that 'chicken' and 'beef' are the first two items, then the remaining items are sorted alphabetically. How would I go about doing this?
irb> my_array.sort_by { |e| [ e == 'chicken' ? 0 : e == 'beef' ? 1 : 2, e ] }
#=> ["chicken", "beef", "fish", "lamb", "mushroom", "tofu"]
This will create a sorting key for each element of the array, and then sort the array elements by their sorting keys. Since the sorting key is an array, it compares by position, so [0, 'chicken'] < [1, 'beef'] < [2, 'apple' ] < [2, 'banana'].
If you don't know what elements you wanted sorted to the front until runtime, you can still use this trick:
irb> promotables = [ 'chicken', 'beef' ]
#=> [ 'chicken', 'beef' ]
irb> my_array.sort_by { |e| [ promotables.index(e) || promotables.size, e ] }
#=> ["chicken", "beef", "fish", "lamb", "mushroom", "tofu"]
irb> promotables = [ 'tofu', 'mushroom' ]
#=> [ 'tofu', 'mushroom' ]
irb> my_array.sort_by { |e| [ promotables.index(e) || promotables.size, e ] }
#=> [ "tofu", "mushroom", "beef", "chicken", "fish", "lamb"]
Mine's a lot more generic and more useful if you get your data only at runtime.
my_array = ['mushroom', 'beef', 'fish', 'chicken', 'tofu', 'lamb']
starters = ['chicken', 'beef']
starters + (my_array.sort - starters)
# => ["chicken", "beef" "fish", "lamb", "mushroom", "tofu"]
Could just do
firsts = ["chicken", "beef"]
[*firsts, *(my_array.sort - firsts)]
#=> ["chicken", "beef", "fish", "lamb", "mushroom", "tofu"]