How to replace an object in Ruby? - ruby

Say I have some deeply nested array structure and a reference to an object inside:
strings = ["1", "2", " 3"]
nested = [[strings] * 10] * 10
reference = nested[0][0][0]
How do I replace the object reference points to with eg. "4"? I need somthing generic that works with arbitrary objects, not String#gsub! and friends. Something like Object#replace(other_obj).

You can't, we don't have (explicit) pointers in Ruby, we have (implicit) references but you can't dereference them to mess with what they contain. Instead, you need to do something like:
inner nested[0][0]
inner[0] = '4'
so that you can work with a reference to the element you want to replace rather than the element itself.
Of course, with the structure in your question, that inner[0] = '4' will replace the first element of strings (and thus every element of nested since it is just a pile of references to the same array that strings references.
Sorry about how overloaded the term reference is here. It is a horrible abuse of English but English itself is an abuse of English :)

Related

In Ruby is there a way to get the index of an item in an array that consists of structs?

With a normal array, I can use the arrayname.find_index('whatimlookingfor') to get the position within the array.
I can't figure out how to do this when the elements of the array are Struct's.
Scenario: I have a struct that consists of an ID and the Filename. In one function I need to find within that array the ID of a different file than the one I'm currently processing. I know the other filename, so what I was hoping that I could do something like:
arrayname.filename.find_index(parsedfilename)
But this obviously fails. Without iterating through the entire array is there a way to quickly reference the index of where the match happens? Or am I out of luck because the array is a collection of structs?
index (same as find_index) takes a block in which you can code up any true/false logic for your finder. To find the index of the first item whose filename does not match parsedfilename...
found_index = items.index { |item| item.filename != parsedfilename }
Many methods which work with Arrays and Enumerables also take blocks.

Understanding hashes

An exercise says:
Create three hashes called person1, person2, and person3, with first
and last names under the keys :first and :last. Then create a params
hash so that params[:father] is person1, params[:mother] is person2,
and params[:child] is person3. Verify that, for example,
params[:father][:first] has the right value.
I did
person1 = {first: "Thom", last: "Bekker"}
person2 = {first: "Kathy", last: "Bekker"}
person2 = {first: "Anessa", last: "Bekker"}
then the params hash in Rails
params = {}
params[:father] = person1
params[:mother] = person2
params[:child] = person3
Now I can ask for father, mother or child's first or last name like so
params[:father][:first] gives me "Thom".
What makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?
I have no way to check if the way I came up with is correct, is there a better way to do the exercise?
Is there a reason why symbol: is better than symbol =>?
Your Return Value is a Single Hash Object
You're misunderstanding the type of object you're getting back. params[:father] returns a single Hash object, not an Array or an Array of hashes. For example:
params[:father]
#=> {:first=>"Thom", :last=>"Bekker"}
params[:father].class
#=> Hash
So, you can't access the missing third element (e.g. :last) because there's no such element within the value of params[:father][:first].
Instead, you could deconstruct the Hash:
first, last = params[:father].values
#=> ["Thom", "Bekker"]
or do something more esoteric like:
p params[:father].values.join " "
#=> "Thom Bekker"
The point is that you have to access the values of the Hash, or convert it to an Array first, rather than treating it directly like an Array and trying to index into multiple values at once.
In Ruby, using square brackets on the Hash or other classes is actually using a method available for an object of that class (this one). When you call these methods in your example, each of these methods will be called and will return its result before the next method is called. So, as you've defined it:
Calling [:father] on params returns the hash represented by person1
[:first] is then called on {first: "Thom", last: "Bekker"}, returning the corresponding value in the hash, "Thom"
[:last] is called on "Thom", which results in an error. Calling square brackets on a string with an integer between them can access the character in a string at that index (person1[:first][0] returns "T"), but "Thom" doesn't have a way of handling the :last symbol inside the square brackets.
There are a number of ways you could get the names printed as you wanted, one of the simplest being combining the string values in person1:
params[:father][:first] + " " + params[:father][:last]
returns "Thom Bekker"
So here's my question, what exactly makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?
Both of these would work
params[:father][:first] + params[:father][:last]
params[:father].values.join(' ')
But maybe it would be better to think about them like the nested structures that they are:
father = params[:father]
name = father[:first] + father[:last]
puts name
To answer your last question, pretend that there's no difference between a hashrocket => and symbol:. This is one where you don't need to care for a long time. Maybe around year 2 start asking this again, but for learning treat them as if they were equivalent.
(Full disclosure, there are differences, but this is a holy war that you really don't want to see played out)

Ruby: Array each loop, save other elements of original array in new array

I am currently trying to compare every element of an array with the others (in Ruby). Those elements are objects of a class. I need to find similarities between them. My idea was to loop through the original array and in this loop creating a new array containing the other elements (not the one of the outer loop) and then loop through this second array and compare every item with the one in the outer each loop.
Here is some pseudocode:
originalArray.each{
|origElement|
tempArray = createNewArray from original array without origElement
tempArray.each{
|differentElement|
Compare origElement with differentElement
}
}
How can I create that tempArray?
I think you should use Array#permutation for this
original_array.permutation(2) { |elements| Compare elements[0] with elements[1] }
First, I want to say bjhaid's answer is beautiful and for your specific instance, it is the one that should be used.
However, I wanted to provide a more general answer that answers the direct question you asked: "How can I create that tempArray?"
If you wanted to delete all values that are equal to the element in the original array, you could simply do:
tempArray = originalArray - [origElement]
However, if you only want to delete that element, you could do:
originalArray.each_with_index {
|origElement, index|
tempArray = originalArray.dup
tempArray.delete_at(index)
tempArray.each{
|differentElement|
Compare origElement with differentElement
}
}
Also, a note on styling. You probably want to use underscores instead of CamelCase for all methods/variables. In the Ruby community, CamelCase is typically reserved for class / module names. You also probably want to keep the "piped-in" variables (called block arguments) on the same line as the beginning of the block. It is certainly not a requirement, but it is an almost universal convention in the Ruby community.
This code snippet would be much more familiar and readable to your typical Ruby dev:
original_array.each_with_index do |orig_element, index|
temp_array = original_array.dup
temp_array.delete_at(index)
temp_array.each do |different_element|
Compare orig_element with different_element
end
end

Ruby object references vs collection references

I was going through The Well Grounded Rubyist and got confused by the following example.
Suppose we have an array of strings:
numbers = ["one", "two", "three"]
If I freeze this array, I can't do the following:
numbers[2] = "four"
That statement is a Runtime error, but this:
numbers[2].replace("four")
is not.
The book explains that in the first of the last two statements, we are trying to access the array. That's what I found confusing because I thought we are trying to access the third element of the array, which is a string object. And how is that different from the last statement?
It's different because in the statement that works you are calling String#replace. As you might expect, a call to Array#replace will fail.
numbers.replace [1,2,3]
TypeError: can't modify frozen array
The object reference at any given array index might be arbitrarily complicated and it's not the job of the frozen array to keep those objects from changing ... it just wants to keep the array from changing. You can see this:
ree-1.8.7> numbers[2].object_id
=> 2149301040
ree-1.8.7> numbers[2].replace "four"
=> "four"
ree-1.8.7> numbers[2].object_id
=> 2149301040
numbers[2] has the same object_id after String#replace runs; the Array did not actually change.
An array is a list of object_id's. String#replace is special - it changes the string but it keeps the object_id. So the list of object_id's does not change and the Array does not detect any change.
You can freeze every string of the array. String#replace would then result in an error.

Are curly brackets used in Lua?

If curly brackets ('{' and '}') are used in Lua, what are they used for?
Table literals.
The table is the central type in Lua, and can be treated as either an associative array (hash table or dictionary) or as an ordinary array. The keys can be values of any Lua type except nil, and the elements of a table can hold any value except nil.
Array member access is made more efficient than hash key access behind the scenes, but the details don't usually matter. That actually makes handling sparse arrays handy since storage only need be allocated for those cells that contain a value at all.
This does lead to a universal 1-based array idiom that feels a little strange to a C programmer.
For example
a = { 1, 2, 3 }
creates an array stored in the variable a with three elements that (coincidentally) have the same values as their indices. Because the elements are stored at sequential indices beginning with 1, the length of a (given by #a or table.getn(a)) is 3.
Initializing a table with non-integer keys can be done like this:
b = { one=1, pi=3.14, ["half pi"]=1.57, [function() return 17 end]=42 }
where b will have entries named "one", "pi", "half pi", and an anonymous function. Of course, looking up that last element without iterating the table might be tricky unless a copy of that very function is stored in some other variable.
Another place that curly braces appear is really the same semantic meaning, but it is concealed (for a new user of Lua) behind some syntactic sugar. It is common to write functions that take a single argument that should be a table. In that case, calling the function does not require use of parenthesis. This results in code that seems to contain a mix of () and {} both apparently used as a function call operator.
btn = iup.button{title="ok"}
is equivalent to
btn = iup.button({title="ok"})
but is also less hard on the eyes. Incidentally, calling a single-argument function with a literal value also works for string literals.
list/ditionary constructor (i.e. table type constructor).
They are not used for code blocks if that's what you mean. For that Lua just uses the end keyword to end the block.
See here
They're used for table literals as you would use in C :
t = {'a', 'b', 'c'}
That's the only common case. They're not used for block delimiters. In a lua table, you can put values of different types :
t={"foo", 'b', 3}
You can also use them as dictionnaries, à la Python :
t={name="foo", age=32}

Resources