arr = [50, 30, "+"]
I would like to move "+" in between 50 and 30 through iteration.
I thought each_with_index would do the trick but so far no luck. This is a part of the process of making Reverse Polish Notation. (If anyone is interested, http://en.wikipedia.org/wiki/Reverse_Polish_notation)
def evaluate(arr)
arr.each_with_index {|ele, index| index-1 if x=="+"}
end
I would like to move operator like =, - and * by one index so it will return 50 - 30. Thanks!
arr.values_at(0, 2, 1)
#=> [50, "+", 30]
arr.values_at(0, 2, 1).join(" ")
#=> "50 + 30"
I'd do it like this:
arr[-1], arr[-2] = arr[-2], arr[-1]
This swaps the last two elements of the array.
You could create a temporary array:
def evaluate(arr)
temp = arr.dup
arr.each_with_index { |ele, index| temp[index-1] = ele }
temp
end
Another way is to repeat the array twice and grab the elements at indices 1-3:
(arr * 2)[1..3]
This doesn't answer your question directly, but if you're looking to implement RPN in Ruby, you don't need to do any array munging. You can iterate your ops and maintain your value stack directly:
def rpn(*ops)
stack = []
ops.each do |op|
case op
when Numeric
stack.push op
else
value = stack.pop
receiver = stack.pop
stack.push receiver.send(op, value)
end
end
stack.first
end
puts rpn 5, 1, 2, "+", 4, "*", "+", 3, "-" # => 14
The fun thing is that since this is Ruby, operations are just messages you send to the receiver, so you can do things beyond basic math - for example, to get the greatest common denominator of two numbers, Ruby provides the "gcd" method, which you can feed into your RPN parser!
puts rpn 64, 24, "gcd" # => 8
Related
For this array: a = [8, 2, 22, 97, 38, 15], how can I get all sub-arrays of length three, in the fashion of a sliding window, without disturbing the order of the values.?
For example, the result should be: [[8,2,22],[2,22,97],[22,97,38],[97,38,15]]
You could pass a parameter for like this to achieve
a.each_con(3)
This returns an Enumeration which you may iterate over. To turn the Enumeration into an array, call the to_a method:
a.each_cons(3).to_a
Here is what I came up with:
def ordered_permutations(array: [1,2,3], length: n)
array = array.dup
[].tap do |result|
(array.count - (length - 1)).times do
result << array[0..(length-1)]
array.shift
end
end
end
p ordered_permutations(array: a, length: 3)
I can't seem to go beyond using Enumerators in a trivial way.
Maybe it's actually more limited than I realize.
Here is an example where I thought Enumerators would be handy, but couldn't implement them:
Let array = [0, 1, 2, "+", 4].
I'm interested in creating the following Enumerator-behavior:
iterate through the array
yield all objects that are not "+"
if it is a "+", delete that element and the previous two elements,
yield their sum, and reset the enumeration sequence to the
beginning.
Maybe the problem is that I can't "delete" something that has already been yielded? In other words, I can't un-yield? I'm interested in this behavior because of its ability to rewind the sequence at any given position after mutating the array (which messes up the order of iteration).
Enumerator does not have a previous method, it does not allow you to skip values while iterating and it does not have a method to delete elements.
So I think that you can't do what you want with the exact workflow you posted although I am sure it is possible to create the behaviour you seek when it is possible to deviate from your workflow.
Summary - this option seems to meet your criteria as expressed:
[0, 1, 2, "+", 4].inject([]) { |n,e| n << (e == "+" ? n.pop(2).reduce(:+) : e) }
# => [0, 3, 4]
Here was my thinking on it...
Option 1:
Use each_with_index and that way you can identify the previous elements easily.
array.each_with_index do |element, index|
your_logic_here
end
Option 2:
Or to avoid mutating the array you could just simply build a new one like this:
new_array = []
array.each do |element|
if element == "+"
ele_sum = new_array.pop(2)
new_array << (ele_sum.reduce :+)
else
new_array << element
end
end
And if you don't find it confusing you can combine the two lines in the if statement to:
new_array << new_array.pop(2).reduce(:+)
Or if you're okay with the ternary operator shorten the whole thing to:
def some_function(array)
new_array = []
array.each { |element| new_array << (element == "+" ? new_array.pop(2).reduce(:+) : element) }
end
> array = [0, 1, 2, "+", 4]
> some_function(array)
# => [0, 3, 4]
Works and tested in irb
...or use inject of course then you can do it all inline:
array.inject([]) { |new_array, element| new_array << (element == "+" ? new_array.pop(2).reduce(:+) : element) }
[0, 1, 2, "+", 4].inject([]) { |n,e| n << (e == "+" ? n.pop(2).reduce(:+) : e) }
# => [0, 3, 4]
But I prefer the expanded version for readability
I try to clean my Code. The first Version uses each_with_index. In the second version I tried to compact the code with the Enumerable.inject_with_index-construct, that I found here.
It works now, but seems to me as obscure as the first code.
Add even worse I don't understand the brackets around element,index in
.. .inject(groups) do |group_container, (element,index)|
but they are necessary
What is the use of these brackets?
How can I make the code clear and readable?
FIRST VERSION -- WITH "each_with_index"
class Array
# splits as good as possible to groups of same size
# elements are sorted. I.e. low elements go to the first group,
# and high elements to the last group
#
# the default for number_of_groups is 4
# because the intended use case is
# splitting statistic data in 4 quartiles
#
# a = [1, 8, 7, 5, 4, 2, 3, 8]
# a.sorted_in_groups(3) # => [[1, 2, 3], [4, 5, 7], [8, 8]]
#
# b = [[7, 8, 9], [4, 5, 7], [2, 8]]
# b.sorted_in_groups(2) {|sub_ary| sub_ary.sum } # => [ [[2, 8], [4, 5, 7]], [[7, 8, 9]] ]
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index do |element, index|
group_number = (index.to_f / average_group_size).floor
groups[group_number] << element
end
groups
end
end
SECOND VERSION -- WITH "inject" AND index
class Array
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index.inject(groups) do |group_container, (element,index)|
group_number = (index.to_f / average_group_size).floor
group_container[group_number] << element
group_container
end
end
end
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.
lines = %w(a b c)
indexes = lines.each_with_index.inject([]) do |acc, (el, ind)|
acc << ind - 1 if el == "b"
acc
end
indexes # => [0]
What is the use of these brackets?
To understand the brackets, first you need to understand how destruction works in ruby. The simplest example I can think of this this:
1.8.7 :001 > [[1,3],[2,4]].each do |a,b|
1.8.7 :002 > puts a, b
1.8.7 :003?> end
1
3
2
4
You should know how each function works, and that the block receives one parameter. So what happens when you pass two parameters? It takes the first element [1,3] and try to split (destruct) it in two, and the result is a=1 and b=3.
Now, inject takes two arguments in the block parameter, so it is usually looks like |a,b|. So passing a parameter like |group_container, (element,index)| we are in fact taking the first one as any other, and destructing the second in two others (so, if the second parameter is [1,3], element=1 and index=3). The parenthesis are needed because if we used |group_container, element, index| we would never know if we are destructing the first or the second parameter, so the parenthesis there works as disambiguation.
9In fact, things works a bit different in the bottom end, but lets hide this for this given question.)
Seems like there already some answers given with good explanation. I want to add some information regards the clear and readable.
Instead of the solution you chose, it is also a possibility to extend Enumerable and add this functionality.
module Enumerable
# The block parameter is not needed but creates more readable code.
def inject_with_index(memo = self.first, &block)
skip = memo.equal?(self.first)
index = 0
self.each_entry do |entry|
if skip
skip = false
else
memo = yield(memo, index, entry)
end
index += 1
end
memo
end
end
This way you can call inject_with_index like so:
# m = memo, i = index, e = entry
(1..3).inject_with_index(0) do |m, i, e|
puts "m: #{m}, i: #{i}, e: #{e}"
m + i + e
end
#=> 9
If you not pass an initial value the first element will be used, thus not executing the block for the first element.
In case, someone is here from 2013+ year, you have each_with_object and with_index for your needs:
records.each_with_object({}).with_index do |(record, memo), index|
memo[record.uid] = "#{index} in collection}"
end
I want to look at every n-th elements in an array. In C++, I'd do this:
for(int x = 0; x<cx; x+=n){
value_i_care_about = array[x];
//do something with the value I care about.
}
I want to do the same in Ruby, but can't find a way to "step". A while loop could do the job, but I find it distasteful using it for a known size, and expect there to be a better (more Ruby) way of doing this.
Ranges have a step method which you can use to skip through the indexes:
(0..array.length - 1).step(2).each do |index|
value_you_care_about = array[index]
end
Or if you are comfortable using ... with ranges the following is a bit more concise:
(0...array.length).step(2).each do |index|
value_you_care_about = array[index]
end
array.each_slice(n) do |e, *_|
value_i_care_about = e
end
Just use step() method from Range class which returns an enumerator
(1..10).step(2) {|x| puts x}
We can iterate while skipping over a range of numbers on every iteration e.g.:
1.step(10, 2) { |i| print "#{i} "}
http://www.skorks.com/2009/09/a-wealth-of-ruby-loops-and-iterators/
So something like:
array.step(n) do |element|
# process element
end
class Array
def step(interval, &block)
((interval -1)...self.length).step(interval) do |value|
block.call(self[value])
end
end
end
You could add the method to the class Array
What about:
> [1, 2, 3, 4, 5, 6, 7].select.each_with_index { |_,i| i % 2 == 0 }
=> [1, 3, 5, 7]
Chaining of iterators is very useful.
This is a great example for the use of the modulo operator %
When you grasp this concept, you can apply it in a great number of different programming languages, without having to know them in and out.
step = 2
["1st","2nd","3rd","4th","5th","6th"].each_with_index do |element, index|
puts element if index % step == 1
end
#=> "2nd"
#=> "4th"
#=> "6th"
(1..4).collect do |x|
next if x == 3
x + 1
end # => [2, 3, nil, 5]
# desired => [2, 3, 5]
If the condition for next is met, collect puts nil in the array, whereas what I'm trying to do is put no element in the returned array if the condition is met. Is this possible without calling delete_if { |x| x == nil } on the returned array?
My code excerpt is heavily abstracted, so looking for a general solution to the problem.
There is method Enumerable#reject which serves just the purpose:
(1..4).reject{|x| x == 3}.collect{|x| x + 1}
The practice of directly using an output of one method as an input of another is called method chaining and is very common in Ruby.
BTW, map (or collect) is used for direct mapping of input enumerable to the output one. If you need to output different number of elements, chances are that you need another method of Enumerable.
Edit: If you are bothered by the fact that some of the elements are iterated twice, you can use less elegant solution based on inject (or its similar method named each_with_object):
(1..4).each_with_object([]){|x,a| a << x + 1 unless x == 3}
I would simply call .compact on the resultant array, which removes any instances of nil in an array. If you'd like it to modify the existing array (no reason not to), use .compact!:
(1..4).collect do |x|
next if x == 3
x
end.compact!
In Ruby 2.7+, it’s possible to use filter_map for this exact purpose. From the docs:
Returns an array containing truthy elements returned by the block.
(0..9).filter_map {|i| i * 2 if i.even? } #=> [0, 4, 8, 12, 16]
{foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } #=> [:foo, :baz]
For the example in the question: (1..4).filter_map { |x| x + 1 unless x == 3 }.
See this post for comparison with alternative methods, including benchmarks.
just a suggestion, why don't you do it this way:
result = []
(1..4).each do |x|
next if x == 3
result << x
end
result # => [1, 2, 4]
in that way you saved another iteration to remove nil elements from the array. hope it helps =)
i would suggest to use:
(1..4).to_a.delete_if {|x| x == 3}
instead of the collect + next statement.
You could pull the decision-making into a helper method, and use it via Enumerable#reduce:
def potentially_keep(list, i)
if i === 3
list
else
list.push i
end
end
# => :potentially_keep
(1..4).reduce([]) { |memo, i| potentially_keep(memo, i) }
# => [1, 2, 4]