I have the following:
article_results.keys do |key|
article_results[key].map! do |a|
a[:filename] = c.filename
a[:sitename] = c.site_name
a
end
end
As I want to add to each element of each array within the hash dynamically, but for some reason a[:filename] and a[:sitename] are blank when they are used.
So I want to know if I should be using .each instead.
Also I guess I'd like to know what's the main difference since they both can be used for side-effects.
I'm adding this as an extra fyi, I'm using ruby 1.8.7 so it would be nice to know how it differs between versions (1.8.7 - 1.9+) as well.
P.s. I know what the difference between .each and .map is, I'm asking specifically about .map!.
#map has a bit different semantics for hashes than it has for arrays (and i think it's not very consistent between versions of ruby). in general if you are looking for an array as a result of some operation - #map is your friend, however if you want hash as a result of some operation - you're better off with #reduce:
article_results.reduce({}) do |hash, (key, value)|
hash.merge(key => value.merge(filename: c.filename,
sitename: c.sitename))
end
alternatively if you don't care how "functional" your code is, you can use #each:
article_results.each do |key, value|
article_results[key].merge!(filename: c.filename,
sitename: c.sitename)
end
Related
First question on stackoverflow :)
I'm going through the Ruby course on Codecademy and I'm stuck on something.
fruits = ["orange", "apple", "banana", "pear", "grapes"]
fruits.sort! {|first, second| second <=> first}
print fruits
I don't know how to phrase this question. On Codecademy the assignment was to set up the array to be displayed in reverse on the console. After some research, I was able to figure it out. I understand how it works and the order to put it in the code not why. I'm aware that "<=>" compares two objects, but how do the items within the array become objects when we don't declare them as such?
Secondly, what is the purpose of writing this code in this way when we could do fruits.sort.reverse?
First question: At various points in its operation the sort method has to compare pairs of objects to see what their relative ordering should be. It does the comparison by applying the block you pass to sort, i.e., {|first, second| second <=> first}. Not sure what you mean by "how do the items within the array become objects when we don't declare them as such?". All data in ruby is an object, so there's no declaration or conversion needed given that all variables are object references.
Second question: Yes, you could do fruits.sort.reverse, but that would require additional work after the sort to do the reverse operation. Also, reverse can't handle more complex sorting tasks, such as sorting people by multiple criteria such as gender & last name, or hair color, height, and weight. Writing your own comparator can handle quite complex orderings.
String literals can be used to create string objects in Ruby, there is no need to use the String class to create the object. The following two are equivalent:
"Hello, world!"
String.new("Hello, world!")
More information can be found here.
Secondly, what is the purpose of writing this code in this way when we could do fruits.sort.reverse?
Please contact Codecademy about this, but I suspect it's for learning more about how <=> works.
I am using Ruby, and I am relearning arrays and trying to better understand them. I know what they are but have never fully utilized them. I have an array, odds, and wanted to double every number in it. I came up with the below solution; however, I wanted to see if there was a more elegant/simple solution to my problem.
odds = [1,3,5,7,9]
odds.each do |x|
odds[odds.index(x)]=x*2
end
end result is odds = [2,6,10,14,18]
You can use the map! enumerator to modify every item in an array:
odds.map!{ |x| x*2}
If you really want to modify in place, and you really want to use each, I guess your approach is as good as any. It doesn't feel idiomatic, but it does meet your stated constraints.
Here are some more common approaches:
Array.map
Mapping the array with map won't modify the original array (it's not in-place), which is often a good thing, but it might not be what you're looking for:
odds.map { |x| x*2 }
Array.map!
If you really do want to modify the original array, you can use map! to map in-place:
odds.map! { |x| x*2 }
Array.each_index
You did ask specifically about each, so if you want to use an each and you want to modify the original array, each_index might be your best bet:
odds.each_index { |i| odds[i] *= 2 }
I'm learning Ruby, and I'm having a problem while making a program.
I have a class "LineAnalyzer" that has 4 parameters (2 provided and 2 calculated). Both calculated params are: #high_wf_count (integer) and #high_wf_words (array).
Then, I have this one:
class Solution < LineAnalyzer
attr_reader :analyzers,
:highest_count_across_lines,
:highest_count_words_across_lines
def initialize
#analyzers = []
end
def analyze_file
File.foreach('test.txt') do |line|
#analyzers << LineAnalyzer.new(line.chomp,#analyzers.length+1)
end
end
def calculate_line_with_highest_frequency
#highest_count_words_across_lines = []
#highest_count_across_lines = #analyzers.max_by do
|a| a.instance_variable_get(:#highest_wf_count)
end .instance_variable_get(:#highest_wf_count)
#highest_count_words_across_lines << #analyzers.each do
|a| a.instance_variable_get(:#highest_wf_count) == #highest_count_across_lines
end .instance_variable_get(:#highest_wf_words)
end
end
The problem is that I cannot append the array #highest_wf_count to #highest_count_words_across_lines in the way I've done (it returns nil). But, I've previously taken the integer #highest_wf_count in the same way perfectly.
Can anyone tell me where's the problem?
Thanks in advance!
It seems that your problem is in this bit of code:
#highest_count_words_across_lines << #analyzers.each do
|a| a.instance_variable_get(:#highest_wf_count) == #highest_count_across_lines
end .instance_variable_get(:#highest_wf_words)
Preferably formatted as:
#highest_count_words_across_lines << #analyzers.each do |analyzer|
analyzer.instance_variable_get(:#highest_wf_count) == #highest_count_across_lines
end.instance_variable_get(:#highest_wf_words)
The problem here is that you are calling .instance_variable_get(:#highest_wf_words) on the result of the :each method.
A few lines above, you are doing something similar, where you call .instance_variable_get(:#highest_wf_count) on the result of the :max_by method, and it is working.
The difference between :max_by and :each is that :max_by returns a single analyzer, whereas :each returns the array of #analyzers over which it is iterating.
When you call :instance_variable_get(:#highest_wf_words) on that array, it's returning nil because an array will not have an instance variable named :#highest_wf_words
That is where your problem exists.
Sidenote:
It is generally not good practice to ever use :instance_variable_get. I would recommend adding to your analyzer class attr_reader :highest_wf_words, :highest_wf_count
Then, instead of calling analyzer.instance_variable_get(:#highest_wf_words), you can just call analyzer.highest_wf_words
There's a lot going on here and most of the code results from going against the grain when writing Ruby. Using instance_variable_get should be an absolute last resort. It's considered highly rude to just reach into an object and pull out a variable. It creates ugly and undesirable inter-dependencies. If that other object wanted to give you that value it would have a method to access it.
The way I see it what you're trying to do boils down to something like this:
def highest_frequency
#analyzers.map do |a|
a.highest_wf_count
end.sort.last
end
Let Analyzer implement highest_wf_count as a method, even if it's just an attr_reader. This gives you the flexibility to change how and when that value is computed. Maybe you don't need to do it when the object is initialized. Maybe it's done in another thread, or it's evaluated lazily.
Whenever possible try and structure your code as a series of straight-forward transformations. Try not to create convoluted, branching, ugly comparisons. Lean on Enumerable whenever possible, it's usually got a method that does exactly what you want, or two that in conjunction do the job perfectly.
This is way more complex than it needs to be (or should be).
Why does Solution subclass LineAnalyzer? And why are you using instance_variable_get? You should define getter methods using attr_reader on the LineAnalyzer class so you can call methods instead of using instance_variable_get, which is a brute force approach that should only be used as a last resort.
I think you should fix this before proceeding.
When you have instance methods created with attr_reader, calculating the max becomes very simple:
highest_count_across_lines = #analyzers.map(&:highest_wf_count).max
I think your error probably is caused by these lines:
#highest_count_words_across_lines << #analyzers.each do
|a| a.instance_variable_get(:#highest_wf_count) == #highest_count_across_lines
end .instance_variable_get(:#highest_wf_words)
I suggest simplifying this code, and the error will probably present itself to you. Did you really mean to append the value returned by each to #highest_count_words_across_lines? This will be an Array of analyzers. The Array class, of course, does not have a variable named :#highest_wf_words.
Again, I think you really need to simplify this code.
Ruby 2.3 introduces a new method on Array and Hash called dig. The examples I've seen in blog posts about the new release are contrived and convoluted:
# Hash#dig
user = {
user: {
address: {
street1: '123 Main street'
}
}
}
user.dig(:user, :address, :street1) # => '123 Main street'
# Array#dig
results = [[[1, 2, 3]]]
results.dig(0, 0, 0) # => 1
I'm not using triple-nested flat arrays. What's a realistic example of how this would be useful?
UPDATE
It turns out these methods solve one of the most commonly-asked Ruby questions. The questions below have something like 20 duplicates, all of which are solved by using dig:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
Ruby Style: How to check whether a nested hash element exists
In our case, NoMethodErrors due to nil references are by far the most common errors we see in our production environments.
The new Hash#dig allows you to omit nil checks when accessing nested elements. Since hashes are best used for when the structure of the data is unknown, or volatile, having official support for this makes a lot of sense.
Let's take your example. The following:
user.dig(:user, :address, :street1)
Is not equivalent to:
user[:user][:address][:street1]
In the case where user[:user] or user[:user][:address] is nil, this will result in a runtime error.
Rather, it is equivalent to the following, which is the current idiom:
user[:user] && user[:user][:address] && user[:user][:address][:street1]
Note how it is trivial to pass a list of symbols that was created elsewhere into Hash#dig, whereas it is not very straightforward to recreate the latter construct from such a list. Hash#dig allows you to easily do dynamic access without having to worry about nil references.
Clearly Hash#dig is also a lot shorter.
One important point to take note of is that Hash#dig itself returns nil if any of the keys turn out to be, which can lead to the same class of errors one step down the line, so it can be a good idea to provide a sensible default. (This way of providing an object which always responds to the methods expected is called the Null Object Pattern.)
Again, in your example, an empty string or something like "N/A", depending on what makes sense:
user.dig(:user, :address, :street1) || ""
One way would be in conjunction with the splat operator reading from some unknown document model.
some_json = JSON.parse( '{"people": {"me": 6, ... } ...}' )
# => "{"people" => {"me" => 6, ... }, ... }
a_bunch_of_args = response.data[:query]
# => ["people", "me"]
some_json.dig(*a_bunch_of_args)
# => 6
It's useful for working your way through deeply nested Hashes/Arrays, which might be what you'd get back from an API call, for instance.
In theory it saves a ton of code that would otherwise check at each level whether another level exists, without which you risk constant errors. In practise you still may need a lot of this code as dig will still create errors in some cases (e.g. if anything in the chain is a non-keyed object.)
It is for this reason that your question is actually really valid - dig hasn't seen the usage we might expect. This is commented on here for instance: Why nobody speaks about dig.
To make dig avoid these errors, try the KeyDial gem, which I wrote to wrap around dig and force it to return nil/default if any error crops up.
Is there an elegant way to express
val a = Array.fill(2,10) {1}
def do_to_elt(i:Int,j:Int) {
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
}
in scala?
I recommend that you not use arrays of arrays for 2D arrays, for three main reasons. First, it allows inconsistency: not all columns (or rows, take your pick) need to be the same size. Second, it is inefficient--you have to follow two pointers instead of one. Third, very few library functions exist that work transparently and usefully on arrays of arrays as 2D arrays.
Given these things, you should either use a library that supports 2D arrays, like scalala, or you should write your own. If you do the latter, among other things, this problem magically goes away.
So in terms of elegance: no, there isn't a way. But beyond that, the path you're starting on contains lots of inelegance; you would probably do best to step off of it quickly.
You just need to check the array at index i with isDefinedAt if it exists:
def do_to_elt(i:Int, j:Int): Unit =
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
EDIT: Missed that part about the elegant solution as I focused on the error in the code before your edit.
Concerning elegance: no, per se there is no way to express it in a more elegant way. Some might tell you to use the pimp-my-library-Pattern to make it look more elegant but in fact it does not in this case.
If your only use case is to execute a function with an element of a multidimensional array when the indices are valid then this code does that and you should use it. You could generalize the method by changing the signature of to take the function to apply to the element and maybe a value if the indices are invalid like this:
def do_to_elt[A](i: Int, j: Int)(f: Int => A, g: => A = ()) =
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j)) else g
but I would not change anything beyond this. This also does not look more elegant but widens your use case.
(Also: If you are working with arrays you mostly do that for performance reasons and in that case it might even be better to not use isDefinedAt but perform validity checks based on the length of the arrays.)