Using transpose with arrays in Ruby? - ruby

I have the following:
table(
[
[
"UnitID",
"First Name",
"Last Name",
"NPS Score",
"Comments",
"emotion",
"polarity"
],
*[
invite_unitid_arr,
invite_name_arr,
invite_lastname_arr,
nps_score_integers,
comment_arr,
SadPanda.emotion(comment_arr),
SadPanda.polarity(comment_arr)
].transpose
]
)
However, SadPanda.emotion(comment_arr) and SadPanda.polarity(comment_arr) return:
undefined method 'gsub!' for #<Array:0x007f8f9b0d40a8>
How can I transpose the array but also use SadPanda.emotion() on each string value within the array?
EDIT:
To be clear, this is what I want as an end result:
[
invite_unitid_arr[0],
invite_name_arr[0],
invite_lastname_arr[0],
nps_score_integers[0],
comment_arr[0],
SadPanda.emotion(comment_arr[0]),
SadPanda.polarity(comment_arr[0])
],
[
invite_unitid_arr[1],
invite_name_arr[1],
invite_lastname_arr[1],
nps_score_integers[1],
comment_arr[1],
SadPanda.emotion(comment_arr[1]),
SadPanda.polarity(comment_arr[1])
]
Etc. etc. The .transpose method does exactly what I need it to do for all values in the array, but I don't know how to pass in comment_arr[0] on the .emotion and .polarity methods and increment that value each time the array is transposed.

To solve the issue:
new_comment_array_emotion = []
new_comment_array_polarity = []
comment_arr.each do |x|
new_comment_array_emotion << SadPanda.emotion(x)
new_comment_array_polarity << SadPanda.polarity(x)
end
table(
[
[
"UnitID",
"First Name",
"Last Name",
"NPS Score",
"Comments",
"emotion",
"polarity"
],
*[
invite_unitid_arr,
invite_name_arr,
invite_lastname_arr,
nps_score_integers,
comment_arr,
new_comment_array_emotion,
new_comment_array_polarity
].transpose
]
)
Feel free to propose a cleaner way of doing this within Ruby.

Related

Two versions of a Ruby function and why there is a difference [closed]

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 2 years ago.
Improve this question
The following two Ruby functions were written by different programmers. The second version was 'updated' for metric users. I am looking for an explanation for why the second version uses the global variable $Wall_Lumber_Size and the # Note that I am not seeking insight into the second coder's mind, but just enquiring how the $ and the # work together.
First:
# display an input dialog and store the results in the global options hash table
def display_global_options_dialog()
parameters = [
# prompt, attr_name, value, enums
[ "Wall Lumber Size", "wall.style", "2x4|2x6|2x8" ],
[ "Wall Plate Height", "wall.height", nil ],
[ "Wall Stud Spacing", "wall.stud_spacing", nil ],
[ "Wall Justification ", "window.justify", "left|center|right" ],
[ "Window Justification ", "window.justify", "left|center|right" ],
[ "Door Justification ", "door.justify", "left|center|right" ],
[ "Header Height", "header_height", nil ],
[ "Header Size", "header_style", "2x4|2x6|4x4|4x6|4x8|4x10|4x12|4x14|6x6|6x8|6x10|8x6|8x8|8x10" ],
[ "Roof Pitch (x/12) ", "pitch", nil ],
[ "Roof Joist Spacing", 'roof.joist_spacing', nil ],
[ "Floor Joist Spacing", 'floor.joist_spacing', nil ],
]
prompts = []
attr_names = []
values = []
enums = []
parameters.each { |a| prompts.push(a[0]); attr_names.push(a[1]); values.push(HouseBuilder::BaseBuilder::GLOBAL_OPTIONS[a[1]]); enums.push(a[2]) }
results = UI.inputbox(prompts, values, enums, 'Global Properties')
if results
i = 0
attr_names.each do |name|
eval("HouseBuilder::BaseBuilder::GLOBAL_OPTIONS['#{name}'] = results[i]")
i = i + 1
end
end
return results
end
Second:
# display an input dialog and store the results in the global options hash table
def display_global_options_dialog()
parameters = [
# prompt, attr_name, value, enums
$Wall_Lumber_Size,
#[ "Wall Lumber Size", "wall.style", "38x38|38x64|38x89|38x140|38x184|38x235|38x286|64x64|64x89|64x140|64x184|64x235|64x286|89x89|89x140|89x184|89x235|89x286" ],
#[ "Wall Lumber Size", "wall.style", $wall_styles.join("|") ],
[ "Wall Plate Height", "wall.height", nil ],
[ "Wall Stud Spacing", "wall.stud_spacing", nil ],
[ "Wall Justification ", "window.justify", "left|center|right" ],
[ "Window Justification ", "window.justify", "left|center|right" ],
[ "Door Justification ", "door.justify", "left|center|right" ],
[ "Header Height", "header_height", nil ],
$Header_Size,
#[ "Header Size", "header_style", "38x38|38x64|38x89|38x140|38x184|38x235|38x286|64x64|64x89|64x140|64x184|64x235|64x286|89x89|89x140|89x184|89x235|89x286" ],
#[ "Header Size", "header_style", $lumber_sections.join("|") ],
#[ "Roof Pitch (x/12) ", "pitch", nil ],
[ "Roof Pitch (deg°) ", "pitch", nil ],
[ "Roof Joist Spacing", 'roof.joist_spacing', nil ],
[ "Floor Joist Spacing", 'floor.joist_spacing', nil ],
]
prompts = []
attr_names = []
values = []
enums = []
parameters.each { |a| prompts.push(a[0]); attr_names.push(a[1]); values.push(HouseBuilder::BaseBuilder::GLOBAL_OPTIONS[a[1]]); enums.push(a[2]) }
results = UI.inputbox(prompts, values, enums, 'Global Properties')
if results
i = 0
attr_names.each do |name|
eval("HouseBuilder::BaseBuilder::GLOBAL_OPTIONS['#{name}'] = results[i]")
i = i + 1
end
end
return results
end
Lines prepended with # are annotations (comments in Ruby) which are ignored at parse time.
Global Variables defined with $ are variables that may be accessed from anywhere in the program regardless of scope
As Max pointed out in his comment, without having access to the code we don't know what the global variable $Wall_Lumber_Size holds. However, you can look at the definition and see what its value actually is.
The global variable ($) and comments (#) are not related whatsoever.

Remove elements from a hash array if a value matches a line in a text file

I have a JSON file with a hash in that looks like this
{
"1": {
"organisation": "Example1",
"name": "Name1",
"items": [
{
"name": "Name1",
"html_url": "URL1",
"results": [
"items go here"
]
},
{
"name": "Name2",
"html_url": "URL2",
"results": [
"Items go here"
]
},
I want to delete elements whose html_url matches a list stored in a text file, I have been toying with a delete-if like this.
#org.each do |key,value|
File.open('views/investigated.txt').each do |line|
value['items'].delete_if { |h| h['html_url'] == line }
end
end
but it doesn't seem to alter the array, I'm completely lost, any help would be much appreciated
#Stefan is right, it's better practice to create a separate array with the lines you'd like to delete from the array:
urls_to_delete = []
File.open('views/investigated.txt').each do |line|
urls_to_delete.push(line)
end
Then use that array to remove the lines from the hash:
#org.each do |key,value|
value['items'].delete_if { |h| urls_to_delete.include?(h['html_url']) }
end
Tested it with your example and does exactly what you're trying to achieve.
Maybe you can delete records in one iteration by using each_key on ˙#org˙ and you dont need new array.
Like this:
#org.each_key do |key|
File.open('views/investigated.txt').each do |line|
line.chomp!
#org[key]['items'].delete_if { |h| h['html_url'] == line }
end
end

Convert an Array of Strings to a Hash in Ruby

I have an Array that contains strings:
["First Name", "Last Name", "Location", "Description"]
I need to convert the Array to a Hash, as in the following:
{"A" => "First Name", "B" => "Last Name", "C" => "Location", "D" => "Description"}
Also, this way too:
{"First Name" => "A", "Last Name" => "B", "Location" => "C", "Description" => "D"}
Any thoughts how to handle this the best way?
You could implement as follows
def string_array_to_hash(a=[],keys=false)
headers = ("A".."Z").to_a
Hash[keys ? a.zip(headers.take(a.count)) : headers.take(a.count).zip(a)]
end
Then to get your initial output it would be
a = ["First Name", "Last Name", "Location", "Description"]
string_array_to_hash a
#=> {"A"=>"First Name", "B"=>"Last Name", "C"=>"Location", "D"=>"Description"}
And second output is
a = ["First Name", "Last Name", "Location", "Description"]
string_array_to_hash a, true
#=> {"First Name"=>"A", "Last Name"=>"B", "Location"=>"C", "Description"=>"D"}
Note: this will work as long as a is less than 27 Objects otherwise you will have to specify a different desired output. This is due to the fact that a) the alphabet only has 26 letters b) Hash objects can only have unique keys.
You could do this:
arr = ["First Name", "Last Name", "Location", "Description"]
letter = Enumerator.new do |y|
l = ('A'.ord-1).chr
loop do
y.yield l=l.next
end
end
#=> #<Enumerator: #<Enumerator::Generator:0x007f9a00878fd8>:each>
h = arr.each_with_object({}) { |s,h| h[letter.next] = s }
#=> {"A"=>"First Name", "B"=>"Last Name", "C"=>"Location", "D"=>"Description"}
h.invert
#=> {"First Name"=>"A", "Last Name"=>"B", "Location"=>"C", "Description"=>"D"}
or
letter = ('A'.ord-1).chr
#=> "#"
h = arr.each_with_object({}) { |s,h| h[letter = letter.next] = s }
#=> {"A"=>"First Name", "B"=>"Last Name", "C"=>"Location", "D"=>"Description"}
When using the enumerator letter, we have
27.times { puts letter.next }
#=> "A"
# "B"
# ...
# "Z"
# "AA"
If you are not being specific about keys name then you could try this out
list = ["First Name", "Last Name", "Location", "Description"]
Hash[list.map.with_index{|*x|x}].invert
Output
{0=>"First Name", 1=>"Last Name", 2=>"Location", 3=>"Description"}
Similar solutions is here.
Or..You also can try this :)
letter = 'A'
arr = ["First Name", "Last Name", "Location", "Description"]
hash = {}
arr.each { |i|
hash[i] = letter
letter = letter.next
}
// => {"First Name"=>"A", "Last Name"=>"B", "Location"=>"C", "Description"=>"D"}
or
letter = 'A'
arr = ["First Name", "Last Name", "Location", "Description"]
hash = {}
arr.each { |i|
hash[letter] = i
letter = letter.next
}
// => {"A"=>"First Name", "B"=>"Last Name", "C"=>"Location", "D"=>"Description"}

Comparing Deep Nested Array of Array of Hashes in Ruby

I have an array of array of hashes which can be nested any level deep.
array = [
[ ['a','2'], ['b','5'] ],
[ ['c','4'], ['d','5'] ],
[ ['e','6'], [f,7] ],
...]
In the first stage I need to compare each consecutive hash - keep one of the elements and discarding the other.
In the second step the selected element of hash 1 have to be compared to selected element of the hash 2. This process has to continue till i am left with just one hashed element.
How do i do this i Ruby ?
thanks a lot for answering
You can do this with ==:
array1 = [
[ ['a','2'], ['b','5'] ],
[ ['c','4'], ['d','5'] ],
[ ['e','6'], ['f',7] ]
]
array2 = [
[ ['a','2'], ['b','5'] ],
[ ['c','4'], ['d','5'] ],
[ ['e','6'], ['f',7] ]
]
array3 = [
[ ['not','equal'] ]
]
array1 == array2
# => true
array2 == array3
# => false
See Array#== for specifics.

Joining arrays of hashes in Ruby

I am trying to join multiple arrays of hashes in ruby using a common key. For example:
country_info = [
{country_id: "US", country_desc: "United States"},
{country_id: "AU", country_desc: "Australia"}
]
country_stats = [
{country_id:"US", pageviews: 150},
{country_id:"AU", pageviews: 200}
]
i_want = [
{country_id: "US", country_desc: "United States", pageviews:150},
{country_id: "AU", country_desc: "Australia", pageviews:200}
]
This is something like the pv.nest function of protovis in Javascript. See: http://protovis-js.googlecode.com/svn/trunk/jsdoc/symbols/pv.Nest.html
how can I do this in Ruby?
If you put all the different hashes into one array, you can use group_by to group together those with the same country_id. You can then use inject with merge to merge those together:
country_info_and_stats = country_info + country_stats
country_info_and_stats.group_by {|x| x[:country_id]}.map do |k,v|
v.inject(:merge)
end
#=> [{:country_id=>"US", :country_desc=>"United States", :pageviews=>150},
# {:country_id=>"AU", :country_desc=>"Australia", :pageviews=>200}]

Resources