reverse order of Array in Ruby with index counter - ruby

I have an array #dates, that are UTC dates, and in increasing order. I want to flip the indices of the array so that the dates are in descending order. I am familiar with JS an Java, and don't know how to either use a pointer/index counter in ruby.
#dates = [//dates are in here already]
#reverseDates = []
#dates.each do |d|
#reverseDates << #dates.last
end
#dates = #reverseDates
Part of the issue as well is that I think it is duplicating the last index of #dates, not moving it to the other array when it pushes.
So I got it it working by prepending the array, but how do you include index counters in Ruby to accomplish this?
#reverseDates = []
#dates.each do |d|
#reverseDates.unshift(d)
end
#dates = #reverseDates

Ruby has reversing an array built in:
#dates.reverse!
From http://ruby-doc.org/core-1.8.7/Array.html#method-i-reverse-21

Related

Map array values to the ruby hash key

here i have the sample code , mapping array to hash and appending hash to array but expected output is missing the array value
data = {"a"=>5,"b"=>["e","f"]}
data1 = [44,55]
s = []
data1.each_with_index do |i,index|
a = data1[index]
data["b"] = i
s << data
end
p s
output:
[{"a"=>5, "b"=>55}, {"a"=>5, "b"=>55}]
Expected output:
[{"a"=>5, "b"=>44}, {"a"=>5, "b"=>55}]
Your main problem is that you are putting the same object reference into each of your array elements. Think of it as putting two keys to the same locker in two different places. If you change the stuff in the locker, both keys will open it, and they will both see the same stuff. So, when you change the value of 'b', you change it for the object in both array elements, because they're the same object.
The solution is to start your block by creating a copy of the data object, changing its 'b' value, and putting the result into the resulting array.
I've also changed your each_with_index to map, because map is best to use when you are transforming the values in the array. Also, you don't need to have the index available in your block; you're just running through the array elements without caring which element you're working with while you're working with it.
data = {"a"=>5,"b"=>["e","f"]}
data1 = [44,55]
s = []
data1.map do |num|
the_copy = data.clone
the_copy['b'] = num
s << the_copy
end
p s

Ruby Nokogiri parsing omit duplicates

I'm parsing XML files and wanting to omit duplicate values from being added to my Array. As it stands, the XML will looks like this:
<vulnerable-software-list>
<product>cpe:/a:octopus:octopus_deploy:3.0.0</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.1</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.2</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.3</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.4</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.5</product>
<product>cpe:/a:octopus:octopus_deploy:3.0.6</product>
</vulnerable-software-list>
document.xpath("//entry[
number(substring(translate(last-modified-datetime,'-.T:',''), 1, 12)) > #{last_imported_at} and
cvss/base_metrics/access-vector = 'NETWORK'
]").each do |entry|
product = entry.xpath('vulnerable-software-list/product').map { |product| product.content.split(':')[-2] }
effected_versions = entry.xpath('vulnerable-software-list/product').map { |product| product.content.split(':').last }
puts product
end
However, because of the XML input, that's parsing quite a bit of duplicates, so I end up with an array like ['Redhat','Redhat','Redhat','Fedora']
I already have the effected_versions taken care of, since those values don't duplicate.
Is there a method of .map to only add unique values?
If you need to get an array of unique values, then just call uniq method to get the unique values:
product =
entry.xpath('vulnerable-software-list/product').map do |product|
product.content.split(':')[-2]
end.uniq
There are many ways to do this:
input = ['Redhat','Redhat','Redhat','Fedora']
# approach 1
# self explanatory
result = input.uniq
# approach 2
# iterate through vals, and build a hash with the vals as keys
# since hashes cannot have duplicate keys, it provides a 'unique' check
result = input.each_with_object({}) { |val, memo| memo[val] = true }.keys
# approach 3
# Similar to the previous, we iterate through vals and add them to a Set.
# Adding a duplicate value to a set has no effect, and we can convert it to array
result = input.each_with_object.(Set.new) { |val, memo| memo.add(val) }.to_a
If you're not familiar with each_with_object, it's very similar to reduce
Regarding performance, you can find some info if you search for it, for example What is the fastest way to make a uniq array?
From a quick test, I see these performing in increasing time. uniq is 5 times faster than each_with_object, which is 25% slower than the Set.new approach. Probably because sort is implemetned using C. I only tested with only an arbitrary input though, so it might not be true for all cases.

Ruby - Sorting of nested array of arrays with integers as strings

I am attempting to perform a sort of the array of arrays below. I am successfully able to perform the actual sort operation using sort_by but I cannot update the original array.
Instead, I am resorting to pushing each modified hash to a new array (array) and then trying to re-integrate/merge it with the original one which I don't think is the right approach for something as simple as sorting string integers... How do I simply sort the below data format? Creating a new object is perfectly acceptable; this does not require an in-place sort operation but either approach is acceptable.
Expected Outcome
My goal is to simply sort ascending the chapter numbers (strings) which are the keys in my hashes. So, for example, Matthew is already in order however Acts should list 6 first, followed by 9. Romans should list 2 first, followed by 15, etc. Most importantly, the order of books (Matthew, Acts, Romans, and Revelation) must remain in tact.
Here's what I've tried:
array = Array.new
data.each do |x|
array << Hash[x.last.sort_by {|k,v| k.to_i }]
end
# 'array' now contains accurate data that has been sorted but it more difficult to re-merge it than to simply sort the original data
Here's my data:
data = [["Matthew",
{"4"=>[{:book=>"Matthew", :verse=>"18-20", :section=>"new_testament"}],
"22"=>[{:book=>"Matthew", :verse=>"37-38", :section=>"new_testament"}]}],
["Acts",
{"9"=>[{:book=>"Acts", :verse=>"8", :section=>"new_testament"}],
"6"=>[{:book=>"Acts", :verse=>"27-28", :section=>"new_testament"}]}],
["Romans",
{"15"=>[{:book=>"Romans", :verse=>"13A", :section=>"new_testament"}],
"2"=>[{:book=>"Romans", :verse=>"4", :section=>"new_testament"}]}],
["Revelation",
{"7"=>[{:book=>"Revelation", :verse=>"9-10", :section=>"new_testament"}],
"2"=>[{:book=>"Revelation", :verse=>"2-5B", :section=>"new_testament"}],
"1"=>[{:book=>"Revelation", :verse=>"9-10", :section=>"new_testament"}]}]]
I think you were just about there... just include the book name in your output.
new_data = []
data.each do |x|
new_data << [ x[0], Hash[x[1].sort_by{|k,_| k.to_i }] ]
end

Swap adjacent elements in array

I am trying to build a method in Ruby that will take in a string that has been split into an array of letters and then iterate through the array, swapping the element at index n with that at index n+1. The method will then join the new array into a string and push it to another array.
Here is an example of what I am looking to do:
string = "teh"
some_method(string)
some ruby magic here
array << new_string
end
Expected output:
["eth", "the"]
This is for a spell checker program I am writing for school. The method will check if letters in a misspelled word are swapped by checking to see if the output array elements are in the dictionary. If they are, it will return the word with that is most likely the correct word. I haven't had any luck finding articles or documentation on how to build such a method in ruby or on an existing method to do this. I've been tinkering with building this method for awhile now but my code isn't behaving anything like what I need. Thanks in advance!
As #Sergio advised, you want to use parallel assignment for this:
def reverse_em(str)
(0...str.size-1).map do |i|
s = str.dup
s[i], s[i+1] = s[i+1], s[i]
s
end
end
candidates = reverse_em "alogrithm"
#=> ["laogrithm", "aolgrithm", "algorithm", "alorgithm",
# "alogirthm", "alogrtihm", "alogrihtm", "alogritmh"]
dictionary_check(candidates)
#=> algorithm
# al·go·rithm
# noun \ˈal-gə-ˌri-thəm\
# a set of steps that are followed in order to solve a
# mathematical problem or to complete a computer process
Without splitting it into arrays then joining to new arrays (because that doesn't seem necessary):
def some_method(string)
swapped_strings = []
(0...string.size-1).each do |i|
temp_string = string.dup
temp_string[i], temp_string[i+1] = temp_string[i+1], temp_string[i]
swapped_strings << temp_string
end
swapped_strings
end

Is this the best way to grab common elements from a Hash of arrays?

I'm trying to get a common element from a group of arrays in Ruby. Normally, you can use the
& operator to compare two arrays, which returns elements that are present or common in both arrays. This is all good, except when you're trying to get common elements from more than two arrays. However, I want to get common elements from an unknown, dynamic number of arrays, which are stored in a hash.
I had to resort to using the eval() method in ruby, which executes a string as actual code. Here's the function I wrote:
def get_common_elements_for_hash_of_arrays(hash) # get an array of common elements contained in a hash of arrays, for every array in the hash.
# ["1","2","3"] & ["2","4","5"] & ["2","5","6"] # => ["2"]
# eval("[\"1\",\"2\",\"3\"] & [\"2\",\"4\",\"5\"] & [\"2\",\"5\",\"6\"]") # => ["2"]
eval_string_array = Array.new # an array to store strings of Arrays, ie: "[\"2\",\"5\",\"6\"]", which we will join with & to get all common elements
hash.each do |key, array|
eval_string_array << array.inspect
end
eval_string = eval_string_array.join(" & ") # create eval string delimited with a & so we can get common values
return eval(eval_string)
end
example_hash = {:item_0 => ["1","2","3"], :item_1 => ["2","4","5"], :item_2 => ["2","5","6"] }
puts get_common_elements_for_hash_of_arrays(example_hash) # => 2
This works and is great, but I'm wondering...eval, really? Is this the best way to do it? Are there even any other ways to accomplish this(besides a recursive function, of course). If anyone has any suggestions, I'm all ears.
Otherwise, Feel free to use this code if you need to grab a common item or element from a group or hash of arrays, this code can also easily be adapted to search an array of arrays.
Behold the power of inject! ;)
[[1,2,3],[1,3,5],[1,5,6]].inject(&:&)
=> [1]
As Jordan mentioned, if your version of Ruby lacks support for &-notation, just use
inject{|acc,elem| acc & elem}
Can't you just do a comparison of the first two, take the result and compare it to the next one etc? That seems to meet your criteria.
Why not do this:
def get_common_elements_for_hash_of_arrays(hash)
ret = nil
hash.each do |key, array|
if ret.nil? then
ret = array
else
ret = array & ret
end
end
ret = Array.new if ret.nil? # give back empty array if passed empty hash
return ret
end

Resources