Perform arithmetic operations on string in Ruby - ruby-on-rails

input: "20+10/5-1*2"
I want to perform arithmetic operations on that string how can I do it without using eval method in ruby?
expected output: 20

While I hesitate to answer an interview question, and I am completely embarrassed by this code, here is one awful way to do it. I made it Ruby-only and avoided Rails helpers because it seemed more of a Ruby task and not a Rails task.
#
# Evaluate a string representation of an arithmetic formula provided only these operations are expected:
# + | Addition
# - | Subtraction
# * | Multiplication
# / | Division
#
# Also assumes only integers are given for numerics.
# Not designed to handle division by zero.
#
# Example input: '20+10/5-1*2'
# Expected output: 20.0
#
def eval_for_interview(string)
add_split = string.split('+')
subtract_split = add_split.map{ |v| v.split('-') }
divide_split = subtract_split.map do |i|
i.map{ |v| v.split('/') }
end
multiply_these = divide_split.map do |i|
i.map do |j|
j.map{ |v| v.split('*') }
end
end
divide_these = multiply_these.each do |i|
i.each do |j|
j.map! do |k, l|
if l == nil
k.to_i
else
k.to_i * l.to_i
end
end
end
end
subtract_these = divide_these.each do |i|
i.map! do |j, k|
if k == nil
j.to_i
else
j.to_f / k.to_f
end
end
end
add_these = subtract_these.map! do |i, j|
if j == nil
i.to_f
else
i.to_f - j.to_f
end
end
add_these.sum
end
Here is some example output:
eval_for_interview('1+1')
=> 2.0
eval_for_interview('1-1')
=> 0.0
eval_for_interview('1*1')
=> 1.0
eval_for_interview('1/1')
=> 1.0
eval_for_interview('1+2-3*4')
=> -9.0
eval_for_interview('1+2-3/4')
=> 2.25
eval_for_interview('1+2*3/4')
=> 2.5
eval_for_interview('1-2*3/4')
=> -0.5
eval_for_interview('20+10/5-1*2')
=> 20.0
eval_for_interview('20+10/5-1*2*4-2/6+12-1-1-1')
=> 31.0

Related

How to convert human readable number to actual number in Ruby?

Is there a simple Rails/Ruby helper function to help you convert human readable numbers to actual numbers?
Such as:
1K => 1000
2M => 2,000,000
2.2K => 2200
1,500 => 1500
50 => 50
5.5M => 5500000
test = {
'1K' => 1000,
'2M' => 2000000,
'2.2K' => 2200,
'1,500' => 1500,
'50' => 50,
'5.5M' => 5500000
}
class String
def human_readable_to_i
multiplier = {'K' => 1_000, 'M' => 1_000_000}[self.upcase[/[KM](?=\z)/]] || 1
value = self.gsub(/[^\d.]/, '')
case value.count('.')
when 0 then value.to_i
when 1 then value.to_f
else 0
end * multiplier
end
end
test.each { |k, v| raise "Test failed" unless k.human_readable_to_i == v }
Try something like this if you have an array of human readable numbers than
array.map do |elem|
elem = elem.gsub('$','')
if elem.include? 'B'
elem.to_f * 1000000000
elsif elem.include? 'M'
elem.to_f * 1000000
elsif elem.include? 'K'
elem.to_f * 1000
else
elem.to_f
end
end
Have a look here as well, you will find many Numbers Helpers
NumberHelper Rails.
Ruby Array human readable to actual

Converting hash ruby objects to positive currency

I have a hash where the keys are the months and I want to convert the objects to positive numbers AND currency.
INPUT
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
OUTPUT
hash = {
12 => 5888.96,
4 => 6346.10,
3 => 6081.76,
2 => 5774.79,
1 => 4454.38
}
#Output should be a float
Any help would be greatly appreciated.
Try
hash.transform_values{|v| v.round(2).abs()}
or
hash.update(hash){|k,v| v.round(2).abs()}
Numeric.abs() can be applied to ensure a number is positive and Float.round(2) will round a float to 2 decimal places. See ruby-doc.org/core-2.1.4/Numeric.html#method-i-abs and ruby-doc.org/core-2.2.2/Float.html#method-i-round for usage examples. Note that round() will not add trailing zeros since that does not affect numerical value, however trailing zeros can be added by formatting, for example:
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
# transform hash values
hash.each do |key, value|
hash[key] = value.abs().round(2)
end
# print the modified hash without formatting the values
hash.each do |key, value|
puts "#{key} => #{value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.1
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38
# print hash with values formatted with precision of 2 digits
hash.each do |key, value|
puts "#{key} => #{'%.2f' % value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.10
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38

Clean way to create a hash with 3 levels of nesting which creates levels if they don't exist

This is what I do now
h = Hash.new { |h1, k1| h1[k1] = Hash.new { |h2, k2| h2[k2] = {} } }
Although it works, it looks kind of ambiguous. Maybe there is a better way to do the same thing?
h = hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
Then you can assign in anyway you like,
h[:a][:b][:c][:d] = 3
Reference: ref
You can create one recursively like this.
def create n
return {} if n == 0
Hash.new {|h, k| h[k] = create(n - 1)}
end
h = create 3
h[1][1][1] = 2
p h[1][1][1] # => 2
p h[2][1][2] # => {}
h[2][1][2] = 3
p h # => {1=>{1=>{1=>2}}, 2=>{1=>{2=>3}}}
Your code is correct. You can just classify it:
class NestedHash < Hash
def initialize(depth)
self.default_proc = Proc.new {|h,k| h[k] = NestedHash.new(depth-1)} if depth && depth > 1
end
end
h = NestedHash.new(3)

A way to round Floats down

Float round rounds it up or down. I always need it to round down.
I have the solution but i dont really like it... Maybe there is a better way.
This is what i want:
1.9999.round_down(2)
#=> 1.99
1.9901.round_down(2)
#=> 1
I came up with this solution but i would like to know if there is a better solution(I dont like that i convert the float twice). Is there already a method for this? Because I found it pretty strange that I couldnt find it.
class Float
def round_down(n=0)
((self * 10**n).to_i).to_f/10**n
end
end
Thanks.
1.9999.to_i
#=> 1
1.9999.floor
#=> 1
answered 1 sec ago fl00r
"%.2f" % 1.93213
#=> 1.93
#kimmmo is right.
class Float
def round_down(n=0)
self.to_s[/\d+\.\d{#{n}}/].to_f
end
end
Based on answer from #kimmmo this should be a little more efficient:
class Float
def round_down n=0
s = self.to_s
l = s.index('.') + 1 + n
s.length <= l ? self : s[0,l].to_f
end
end
1.9991.round_down(3)
=> 1.999
1.9991.round_down(2)
=> 1.99
1.9991.round_down(0)
=> 1.0
1.9991.round_down(5)
=> 1.9991
or based on answer from #steenslag, probably yet more efficient as there is no string conversion:
class Float
def round_down n=0
n < 1 ? self.to_i.to_f : (self - 0.5 / 10**n).round(n)
end
end
Looks like you just want to strip decimals after n
class Float
def round_down(n=0)
int,dec=self.to_s.split('.')
"#{int}.#{dec[0...n]}".to_f
end
end
1.9991.round_down(3)
=> 1.999
1.9991.round_down(2)
=> 1.99
1.9991.round_down(0)
=> 1.0
1.9991.round_down(10)
=> 1.9991
(Edit: slightly more efficient version without the regexp)
You could use the floor method
http://www.ruby-doc.org/core/classes/Float.html#M000142
For anybody viewing this question in modern times (Ruby 2.4+), floor now accepts an argument.
> 1.9999.floor(1)
=> 1.9
> 1.9999.floor(2)
=> 1.99
> 1.9999.floor(3)
=> 1.999
> 1.9999.ceil(2)
=> 2.0
In Ruby 1.9:
class Float
def floor_with_prec(prec = 0)
(self - 0.5).round(prec)
end
end
class Float
def rownd_down(digits = 1)
("%.#{digits+1}f" % self)[0..-2].to_f
end
end
> 1.9991.rownd_down(3)
=> 1.999
> 1.9991.rownd_down(2)
=> 1.99
> 1.9991.rownd_down(10)
> 1.9991
Found a bug for the answers that try to calculate float in round_down method.
> 8.7.round_down(1)
=> 8.7
> 8.7.round_down(2)
=> 8.69
you can use bigdecimal, integer or maybe string to do all the math but float.
> 8.7 - 0.005
=> 8.694999999999999
Here is my solution:
require 'bigdecimal'
class Float
def floor2(n = 0)
BigDecimal.new(self.to_s).floor(n).to_f
end
end
> 8.7.floor2(1)
=> 8.7
> 8.7.floor2(2)
=> 8.7
> 1.9991.floor(3)
=> 1.999
> 1.9991.floor(2)
=> 1.99
> 1.9991.floor(1)
=> 1.9
class Float
def round_down(n)
num = self.round(n)
num > self ? (num - 0.1**n) : num
end
end
56.0.round_down(-1) = 50. Works with negative numbers as well, if you agree that rounding down makes a number smaller: -56.09.round_down(1) = -56.1.
Found this article helpful: https://richonrails.com/articles/rounding-numbers-in-ruby
Here are the round up and down methods:
class Float
def round_down(exp = 0)
multiplier = 10 ** exp
((self * multiplier).floor).to_f/multiplier.to_f
end
def round_up(exp = 0)
multiplier = 10 ** exp
((self * multiplier).ceil).to_f/multiplier.to_f
end
end
This worked for me.
> (1.999).to_i.to_f
For rounding up you could just use
> (1.999+1).to_i.to_f

Magic First and Last Indicator in a Loop in Ruby/Rails?

Ruby/Rails does lots of cool stuff when it comes to sugar for basic things, and I think there's a very common scenario that I was wondering if anyone has done a helper or something similar for.
a = Array.new(5, 1)
a.each_with_index do |x, i|
if i == 0
print x+1
elsif i == (a.length - 1)
print x*10
else
print x
end
end
Pardon the ugliness, but this gets at what one might want... is there a ruby way to do something to the first and last of a loop?
[EDIT] I think ideally this would be an extension on Array with parameters (array instance, all elements function, first elements function, last elements function)... but I'm open to other thoughts.
You could grab the first and last elements and process them differently, if you like.
first = array.shift
last = array.pop
process_first_one
array.each { |x| process_middle_bits }
process_last_one
If the code for the first and last iteration has nothing in common with the code for the other iterations, you could also do:
do_something( a.first )
a[1..-2].each do |x|
do_something_else( x )
end
do_something_else_else( a.last )
If the different cases have some code in common, your way is fine.
What if you could do this?
%w(a b c d).each.with_position do |e, position|
p [e, position] # => ["a", :first]
# => ["b", :middle]
# => ["c", :middle]
# => ["d", :last]
end
Or this?
%w(a, b, c, d).each_with_index.with_position do |(e, index), position|
p [e, index, position] # => ["a,", 0, :first]
# => ["b,", 1, :middle]
# => ["c,", 2, :middle]
# => ["d", 3, :last]
end
In MRI >= 1.8.7, all it takes is this monkey-patch:
class Enumerable::Enumerator
def with_position(&block)
state = :init
e = nil
begin
e_last = e
e = self.next
case state
when :init
state = :first
when :first
block.call(e_last, :first)
state = :middle
when :middle
block.call(e_last, :middle)
end
rescue StopIteration
case state
when :first
block.call(e_last, :first)
when :middle
block.call(e_last, :last)
end
return
end while true
end
end
It's got a little state engine because it must look ahead one iteration.
The trick is that each, each_with_index, &c. return an Enumerator if given no block. Enumerators do everything an Enumerable does and a bit more. But for us, the important thing is that we can monkey-patch Enumerator to add one more way to iterate, "wrapping" the existing iteration, whatever it is.
Or a tiny little Domain Specific Language:
a = [1, 2, 3, 4]
FirstMiddleLast.iterate(a) do
first do |e|
p [e, 'first']
end
middle do |e|
p [e, 'middle']
end
last do |e|
p [e, 'last']
end
end
# => [1, "first"]
# => [2, "middle"]
# => [3, "middle"]
# => [4, "last"]
and the code that makes it go:
class FirstMiddleLast
def self.iterate(array, &block)
fml = FirstMiddleLast.new(array)
fml.instance_eval(&block)
fml.iterate
end
attr_reader :first, :middle, :last
def initialize(array)
#array = array
end
def first(&block)
#first = block
end
def middle(&block)
#middle = block
end
def last(&block)
#last = block
end
def iterate
#first.call(#array.first) unless #array.empty?
if #array.size > 1
#array[1..-2].each do |e|
#middle.call(e)
end
#last.call(#array.last)
end
end
end
I started thinking, "if only you could pass multiple blocks to a Ruby function, then you could have a slick and easy solution to this question." Then I realized that DSL's play little tricks that are almost like passing multiple blocks.
As many have pointed out, each_with_index seems to be the key to this. I have this code block that I liked.
array.each_with_index do |item,index|
if index == 0
# first item
elsif index == array.length-1
# last item
else
# middle items
end
# all items
end
Or
array.each_with_index do |item,index|
if index == 0
# first item
end
# all items
if index == array.length-1
# last item
end
end
Or by Array extensions
class Array
def each_with_position
array.each_with_index do |item,index|
if index == 0
yield item, :first
elsif index == array.length-1
yield item, :last
else
yield item, :middle
end
end
end
def each_with_index_and_position
array.each_with_index do |item,index|
if index == 0
yield item, index, :first
elsif index == array.length-1
yield item, index, :last
else
yield item, index, :middle
end
end
end
def each_with_position_and_index
array.each_with_index do |item,index|
if index == 0
yield item, :first, index
elsif index == array.length-1
yield item, :last, index
else
yield item, :middle, index
end
end
end
end
If you are willing to add some boilerplate, you can add something like this to the array class:
class Array
def each_fl
each_with_index do |x,i|
yield [i==0 ? :first : (i==length-1 ? :last : :inner), x]
end
end
end
and then anywhere you need to, you get the following syntax:
[1,2,3,4].each_fl do |t,x|
case t
when :first
puts "first: #{x}"
when :last
puts "last: #{x}"
else
puts "otherwise: #{x}"
end
end
for the following output:
first: 1
otherwise: 2
otherwise: 3
last: 4
There's no "do this the (first|last) time" syntax in Ruby. But if you're looking for succinctness, you could do this:
a.each_with_index do |x, i|
print (i > 0 ? (i == a.length - 1 ? x*10 : x) : x+1)
end
The result is what you'd expect:
irb(main):001:0> a = Array.new(5,1)
=> [1, 1, 1, 1, 1]
irb(main):002:0> a.each_with_index do |x,i|
irb(main):003:1* puts (i > 0 ? (i == a.length - 1 ? x*10 : x) : x+1)
irb(main):004:1> end
2
1
1
1
10
Interesting question, and one I've thought a bit about as well.
I think you'd have to create three different blocks/procs/whatever they're called, and then create a method that calls the correct block/proc/whatever. (Sorry for the vagueness - I'm not yet a black belt metaprogrammer) [Edit: however, I've copied from someone who is at the bottom)
class FancyArray
def initialize(array)
#boring_array = array
#first_code = nil
#main_code = nil
#last_code = nil
end
def set_first_code(&code)
#first_code = code
end
def set_main_code(&code)
#main_code = code
end
def set_last_code(&code)
#last_code = code
end
def run_fancy_loop
#boring_array.each_with_index do |item, i|
case i
when 0 then #first_code.call(item)
when #boring_array.size - 1 then #last_code.call(item)
else #main_code.call(item)
end
end
end
end
fancy_array = FancyArray.new(["Matti Nykanen", "Erik Johnsen", "Michael Edwards"])
fancy_array.set_first_code {|item| puts "#{item} came first in ski jumping at the 1988 Winter Olympics"}
fancy_array.set_main_code {|item| puts "#{item} did not come first or last in ski jumping at the 1988 Winter Olympics"}
fancy_array.set_last_code {|item| puts "#{item} came last in ski jumping at the 1988 Winter Olympics"}
fancy_array.run_fancy_loop
produces
Matti Nykanen came first in ski jumping at the 1988 Winter Olympics
Erik Johnsen did not come first or last in ski jumping at the 1988 Winter Olympics
Michael Edwards came last in ski jumping at the 1988 Winter Olympics
Edit: Svante's answer (with molf's suggestion) to a related question shows how to pass in multiple code blocks to a single method:
class FancierArray < Array
def each_with_first_last(first_code, main_code, last_code)
each_with_index do |item, i|
case i
when 0 then first_code.call(item)
when size - 1 then last_code.call(item)
else main_code.call(item)
end
end
end
end
fancier_array = FancierArray.new(["Matti Nykanen", "Erik Johnsen", "Michael Edwards"])
fancier_array.each_with_first_last(
lambda {|person| puts "#{person} came first in ski jumping at the 1988 Winter Olympics"},
lambda {|person| puts "#{person} did not come first or last in ski jumping at the 1988 Winter Olympics"},
lambda {|person| puts "#{person} came last in ski jumping at the 1988 Winter Olympics"})
I needed this functionality from time to time, so I crafted a little class for that purpose.
The latest version is at: https://gist.github.com/3823837
Sample:
("a".."m").to_a.each_pos do |e|
puts "Char\tfirst?\tlast?\tprev\tnext\twrapped?\tindex\tposition" if e.first?
print "#{e.item}\t"
print "#{e.first?}\t"
print "#{e.last?}\t"
print "#{e.prev}\t"
print "#{e.next}\t"
print "#{e.wrapped?}\t\t"
print "#{e.index}\t"
puts "#{e.position}\t"
end
# Char first? last? prev next wrapped? index position
# a true false b false 0 1
# b false false a c true 1 2
# c false false b d true 2 3
# d false false c e true 3 4
# e false false d f true 4 5
# f false false e g true 5 6
# g false false f h true 6 7
# h false false g i true 7 8
# i false false h j true 8 9
# j false false i k true 9 10
# k false false j l true 10 11
# l false false k m true 11 12
# m false true l false 12 13
{
a: "0",
b: "1",
c: "2",
d: "3",
e: "4",
f: "5",
g: "6",
h: "7",
i: "8",
j: "9",
k: "10",
l: "11",
m: "12",
}.each_pos do |(k, v), e|
puts "KV\tChar\t\tfirst?\tlast?\tprev\t\tnext\t\twrapped?\tindex\tposition" if e.first?
print "#{k} => #{v}\t"
print "#{e.item}\t"
print "#{e.first?}\t"
print "#{e.last?}\t"
print "#{e.prev || "\t"}\t"
print "#{e.next || "\t"}\t"
print "#{e.wrapped?}\t\t"
print "#{e.index}\t"
puts "#{e.position}\t"
end
# KV Char first? last? prev next wrapped? index position
# a => 0 [:a, "0"] true false [:b, "1"] false 0 1
# b => 1 [:b, "1"] false false [:a, "0"] [:c, "2"] true 1 2
# c => 2 [:c, "2"] false false [:b, "1"] [:d, "3"] true 2 3
# d => 3 [:d, "3"] false false [:c, "2"] [:e, "4"] true 3 4
# e => 4 [:e, "4"] false false [:d, "3"] [:f, "5"] true 4 5
# f => 5 [:f, "5"] false false [:e, "4"] [:g, "6"] true 5 6
# g => 6 [:g, "6"] false false [:f, "5"] [:h, "7"] true 6 7
# h => 7 [:h, "7"] false false [:g, "6"] [:i, "8"] true 7 8
# i => 8 [:i, "8"] false false [:h, "7"] [:j, "9"] true 8 9
# j => 9 [:j, "9"] false false [:i, "8"] [:k, "10"] true 9 10
# k => 10 [:k, "10"] false false [:j, "9"] [:l, "11"] true 10 11
# l => 11 [:l, "11"] false false [:k, "10"] [:m, "12"] true 11 12
# m => 12 [:m, "12"] false true [:l, "11"] false 12 13
Actual class:
module Enumerable
# your each_with_position method
def each_pos &block
EachWithPosition.each(self, &block)
end
end
class EachWithPosition
attr_reader :index
class << self
def each *a, &b
handler = self.new(*a, :each, &b)
end
end
def initialize collection, method, &block
#index = 0
#item, #prev, #next = nil
#collection = collection
#callback = block
self.send(method)
end
def count
#collection.count
end
alias_method :length, :count
alias_method :size, :count
def rest
count - position
end
def first?
#index == 0
end
def last?
#index == (count - 1)
end
def wrapped?
!first? && !last?
end
alias_method :inner?, :wrapped?
def position
#index + 1
end
def prev
#prev
end
def next
#next
end
def current
#item
end
alias_method :item, :current
alias_method :value, :current
def call
if #callback.arity == 1
#callback.call(self)
else
#callback.call(#item, self)
end
end
def each
#collection.each_cons(2) do |e, n|
#prev = #item
#item = e
#next = n
self.call
#index += 1
# fix cons slice behaviour
if last?
#prev, #item, #next = #item, #next, nil
self.call
#index += 1
end
end
end
end
KISS
arr.each.with_index do |obj, index|
p 'first' if index == 0
p 'last' if index == arr.count-1
end
If you don't mind that the "last" action happens before the stuff in the middle, then this monkey-patch:
class Array
def for_first
return self if empty?
yield(first)
self[1..-1]
end
def for_last
return self if empty?
yield(last)
self[0...-1]
end
end
Allows this:
%w(a b c d).for_first do |e|
p ['first', e]
end.for_last do |e|
p ['last', e]
end.each do |e|
p ['middle', e]
end
# => ["first", "a"]
# => ["last", "d"]
# => ["middle", "b"]
# => ["middle", "c"]
I could not resist :) This is not tuned for performance although i guess it is should not be much slower than most of the other answers here. It's all about the sugar!
class Array
class EachDSL
attr_accessor :idx, :max
def initialize arr
self.max = arr.size
end
def pos
idx + 1
end
def inside? range
range.include? pos
end
def nth? i
pos == i
end
def first?
nth? 1
end
def middle?
not first? and not last?
end
def last?
nth? max
end
def inside range
yield if inside? range
end
def nth i
yield if nth? i
end
def first
yield if first?
end
def middle
yield if middle?
end
def last
yield if last?
end
end
def each2 &block
dsl = EachDSL.new self
each_with_index do |x,i|
dsl.idx = i
dsl.instance_exec x, &block
end
end
end
Example 1:
[1,2,3,4,5].each2 do |x|
puts "#{x} is first" if first?
puts "#{x} is third" if nth? 3
puts "#{x} is middle" if middle?
puts "#{x} is last" if last?
puts
end
# 1 is first
#
# 2 is middle
#
# 3 is third
# 3 is middle
#
# 4 is middle
#
# 5 is last
Example 2:
%w{some short simple words}.each2 do |x|
first do
puts "#{x} is first"
end
inside 2..3 do
puts "#{x} is second or third"
end
middle do
puts "#{x} is middle"
end
last do
puts "#{x} is last"
end
end
# some is first
# short is second or third
# short is middle
# simple is second or third
# simple is middle
# words is last
Partition the array into ranges where elements within each range are supposed to behave different. Map each range thus created to a block.
class PartitionEnumerator
include RangeMaker
def initialize(array)
#array = array
#handlers = {}
end
def add(range, handler)
#handlers[range] = handler
end
def iterate
#handlers.each_pair do |range, handler|
#array[range].each { |value| puts handler.call(value) }
end
end
end
Could create ranges by hand, but these helpers below make it easier:
module RangeMaker
def create_range(s)
last_index = #array.size - 1
indexes = (0..last_index)
return (indexes.first..indexes.first) if s == :first
return (indexes.second..indexes.second_last) if s == :middle
return (indexes.last..indexes.last) if s == :last
end
end
class Range
def second
self.first + 1
end
def second_last
self.last - 1
end
end
Usage:
a = [1, 2, 3, 4, 5, 6]
e = PartitionEnumerator.new(a)
e.add(e.create_range(:first), Proc.new { |x| x + 1 } )
e.add(e.create_range(:middle), Proc.new { |x| x * 10 } )
e.add(e.create_range(:last), Proc.new { |x| x } )
e.iterate
I see a lot of hacks here that are pretty close, but all heavily dependent on the given iterator having a fixed size and NOT being an iterator. I'd like to also propose saving the previous element as you iterate through to know the first/last element that was iterated over.
previous = {}
elements.each do |element|
unless previous.has_key?(:element)
# will only execute the first time
end
# normal each block here
previous[:element] = element
end
# the last element will be stored in previous[:element]
If you know the items in the array are unique (unlike this case), you can do this:
a = [1,2,3,4,5]
a.each_with_index do |x, i|
if x == a.first
print x+1
elsif x == a.last
print x*10
else
print x
end
end
Sometimes a for loop is just your best option
if(array.count > 0)
first= array[0]
#... do something with the first
cx = array.count -2 #so we skip the last record on a 0 based array
for x in 1..cx
middle = array[x]
#... do something to the middle
end
last = array[array.count-1]
#... do something with the last item.
end
I know this question was answered, but this method has no side effects, and doesn't check if the 13th, 14th, 15th.. 10thousandth, 10,001th... record is the first record, or the last.
Previous answers would have failed the assignment in any data structures class.

Resources