5

Let's say I have an array of random numbers in no particular order. Let's say these are the ID #'s for people who ran in a marathon, and they're added to the array in the order they finish, something like:

race1 = [8, 102, 67, 58, 91, 16, 27]
race2 = [51, 31, 7, 15, 99, 58, 22]

This is a simplified and somewhat contrived example, but I think it conveys the basic idea.

Now a couple questions:

First, how could I get the IDs that are before and after a particular entry? Let's say I am looking at runner 58 and I want to know who finished before and after him.

race1, runner58: previous finisher=67, next finisher=91
race2, runner58: previous finisher=99, next finisher=22

Second, if I'm looking at the person who finished first or last, how can I have the "next" or "previous" loop back around the array?

race1, runner8: previous finisher=27, next finisher=102
race2, runner22: previous finisher=58, next finisher=51

Lastly, I'd like to show what position each runner finished in. Given just the array and a value in it, how can I find out what 'ordinal' position it is in the array? Ie:

race1: runner8=1st, runner102=2nd, runner67=3rd ... runner27=last

Thanks very much!

5 Answers 5

7

First & Second:

index = race1.find_index(58)
if !index.nil?
  puts "#{race1[index-1], #{race1[index+1] || race1[0]}"
end

Lastly:

gem install linguistics

then

require 'linguistics'
Linguistics::use( :en )
race1.each_with_index {|runner, i| puts "runner#{runner}=#{(i+1).en.ordinal}"}
Sign up to request clarification or add additional context in comments.

2 Comments

What condition is the nil guard in race1[index-1] || race1[-1] supposed to catch?
Nice tip on the linguistics gem. Thanks!
5

For items #1 and #2 I would create a method which returns the previous and next elements by id, wrapping automatically for the first and last, e.g.:

class Array
  def prev_next(id)
    idx = self.index(id)
    raise Error.new("no racer with id #{id}") unless idx
    [self[idx-1], self[(idx+1)%self.size]]
  end
end
race1.prev_next(58) # => [67, 91]
race1.prev_next(8) # => [27, 102]

Note that the only possible negative index, -1, actually rolls to the end thanks to Ruby's array.slice and by using the modulus of the array size we can adjust for wrapping over the end. For the third item, ordinalization can be done like so:

class Integer
  def ordinalize
    s = self.to_s
    case s
      when /1[123]$/ then s + 'th'
      when /1$/ then s + 'st'
      when /2$/ then s + 'nd'
      when /3$/ then s + 'rd'
      else s + 'th'
    end
  end
end
race1.each_with_index {|x,i| puts "runner#{x}=#{(i+1).ordinalize}"}
# runner8=1st
# runner102=2nd
# runner67=3rd
# ...

3 Comments

Why a regular expression when you are dealing with a fixnum?!
@Jonas Elfström: but for integer 21 we want "21st" not "21th". I could do some integer arithmetic to accomplish the same thing but the solution is more clear to me when considering strings.
Ah, I was completely off track.
2

The find_index method will probably your best bet here.

runner_index = race.find_index finisher_number #find the index of the racer
previous_runner = race[runner_index - 1] #a negative index will wrap around
next_runner = race[runner_index + 1] || race[0] #use a null guard to wrap to the front

1 Comment

it is synonym of index method
0

Hello I don't know exactly what you want to do but if you are using ruby 1.9 you should look at the rotate method and if you are using ruby 1.8.7, you should try to build something around the index method like

race1[race1.index(58) +1] will give 98 (the next one)
race1[race1.index(58) -1] will give 67 (the previous one)

You need to tweak a little bit to simulate the rotate (by testing the value of the returned indice compared to the size of the array or to 0)

Comments

0

First & Second:

race1.rotate(race1.index(58) + 1).first # next
race1.rotate(race1.index(58) - 1).first # previous

Credit: saw this on this post: http://jamonholmgren.com/rubymotion-react-pattern/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.