Ruby inject with index and brackets
What is the use of these brackets?
It's a very nice feature of ruby. I call it "destructuring array assignment", but it probably has an official name too.
Here's how it works. Let's say you have an array
arr = [1, 2, 3]
Then you assign this array to a list of names, like this:
a, b, c = arr
a # => 1
b # => 2
c # => 3
You see, the array was "destructured" into its individual elements. Now, to the each_with_index
. As you know, it's like a regular each
, but also returns an index. inject
doesn't care about all this, it takes input elements and passes them to its block as is. If input element is an array (elem/index pair from each_with_index
), then we can either take it apart in the block body
sorted.each_with_index.inject(groups) do |group_container, pair|
element, index = pair
# or
# element = pair[0]
# index = pair[1]
# rest of your code
end
Or destructure that array right in the block signature. Parentheses there are necessary to give ruby a hint that this is a single parameter that needs to be split in several.
Hope this helps.
Ruby inject with initial being a hash
Your block needs to return the accumulating hash:
['a', 'b'].inject({}) {|m,e| m[e] = e; m }
Instead, it's returning the string 'a' after the first pass, which becomes m
in the next pass and you end up calling the string's []=
method.
Ruby `each_with_object` with index
Instead of
|arr, hash|
you can do
|(v, i), hash|
Ruby each_with_index offset
Actually, Enumerator#with_index
receives offset as an optional parameter:
[:foo, :bar, :baz].to_enum.with_index(1).each do |elem, i|
puts "#{i}: #{elem}"
end
outputs:
1: foo
2: bar
3: baz
BTW, I think it is there only in 1.9.2.
Does using curly braces go against the Ruby way?
While some people go with "braces for one-liners, do-end for multi-liners", I personally find the following rule the most logical:
- use
do-end
when your block has side-effects (typically, witheach
and related methods) and - use braces when your block is without side-effects (
map
,inject
and alike)
This logic goes well with method chaining issue that Matt wrote about.
One benefit of this approach is that it is going to make you think about side-effects every time you write a block, and they are very important, although sometimes overlooked by coders with no functional programming background.
Another way to put it, without involving side-effects terminology would be:
- use
do-end
for blocks that perform - use
{
and}
for blocks that return
Here are couple of articles with more info:
http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc
http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace
Ruby dynamically updating value in nested array
Your iteration is almost there, you just need to stop one step before you run through path
so that you can have the array you need to modify rather than the element.
So split the path
into the pieces you want:
*p, target = path
# [3], 1
Then use #inject
to find the array:
ary = p.inject(example) { |i, a| a[i] }
# [3, 4]
and then do your assignment:
ary[target] = 9
Of course you'll need to add some logic to deal with the unexpected such as path
leading you to a non-array element or path
not matching the structure of example
(consider path = [11, 6, 23]
in your example).
You could also use #dig
instead of #inject
:
ary = example.dig(*p)
ary[target] = 9
# or
example.dig(*p)[target] = 9
That would take care of some of the problematic path
s and you'd be left with deciding what to do if ary.nil?
.
Ruby Syntax: Bitmask
Basically the index
call converts the given roles to integers by determining their position in the array of ROLES
. 2 is then raised to the power of this index and inject
simply sums the the results.
Put simply
Step 1 is to get roles that are found in ROLES by using &
to se which values in the two arrays match.
Step 2, for each matching role compute 2**index. Map returns an array of these values.
Step 3, sum the array to get the final integer.
The idea is to compute a unique integer for each combination of roles.
The getter simply unwinds the process returning the combination of roles that match.
Ruby push a hash into an array with out curly braces
You method expects an hash (not an array of hashes). Therefore you have to use a hash to build your params:
parameters = { :key1 => value1 }
parameters[:key2] = value2
somefunction parameters
Related Topics
Anything Speaking Against the Bitnami.Org Ruby/Rails/Redmine Stack
Converting External CSS to Inline CSS for Mail in Rails
What Do I Need to Do to Get Hash.From_Xml() to Work
Setting the Environment in Gemfile for Bundling Install/Update Based on a Customize File
How to Restart Rails from Within Rails
Using Ruby CSV to Extract One Column
How to Send Mail with Ruby Over Smtp with Ssl (Not with Rails, No Tls for Gmail)
Which Ruby Rest API Client for Neo4J
Ruby on Rails: Two References with Different Name to the Same Model
Ruby: How to Join Elements of an Array Together with a Prefix
Update Rails to a Specific Version
Using Ruby 2.0 on Amazon Opsworks
Rails 5, "Nil Is Not a Valid Asset Source"
Ways to Define a Global Method in Ruby
Ruby on Rails Collection Select - How to Pre-Select the Right Value