july
july

Reputation: 33

Insert into array at specific position based on array content Ruby

I have an array of objects that are sorted by one of the attributes of this object, and I want to insert another object in there at a position that is determined by that attribute of the object.

Basically, something like:
foo = [User(score: 10), User(score: 8), User(score: 5), User(score: 1)]
And in that array, I want to insert:
bar = User(score: 6)
At the correct index, so in this case at index 2.

I could push it to the array and then sort_by, but I was wondering if there is a better solution for this problem (some kind of insert method where you can pass a block to define the index).

Thanks in advance :)

Upvotes: 2

Views: 6067

Answers (2)

Rahul
Rahul

Reputation: 1505

You could find index and then insert if you wanna avoid a full sort. Something like -

insert_index = foo.index { |x| x.score <= new_user.score } || -1
foo.insert(insert_index, new_user)

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110675

Code

def insert_new(arr, new_instance)
  arr.insert(arr.index { |instance| new_instance.score >= instance.score } || -1,
    new_instance)
end

Example

class A
  def initialize(user, score)
    @user, @score = user, score
  end
end

arr = [A.new("Hank", 10), A.new("Lois", 8), A.new("Billy-Bob", 6),
       A.new("Trixy", 4)]
  #=> [#<A:0x007fad7b02fd70 @user="Hank", @score=10>,
  #    #<A:0x007fad7b02fcf8 @user="Lois", @score=8>,
  #    #<A:0x007fad7b02fc80 @user="Billy-Bob", @score=6>,
  #    #<A:0x007fad7b02fbe0 @user="Trixy", @score=4>]

insert_new(arr, A.new("Hubert", 7))
  #=> [#<A:0x007fad7a027450 @user="Hank", @score=10>,
  #    #<A:0x007fad7a0273b0 @user="Lois", @score=8>,
  #    #<A:0x007fad7a850b90 @user="Hubert", @score=7>,
  #    #<A:0x007fad7a027310 @user="Billy-Bob", @score=6>,
  #    #<A:0x007fad7a027270 @user="Trixy", @score=4>] 
insert_new(arr, A.new("Zelda", 2))
  #=> [#<A:0x007fad7a027450 @user="Hank", @score=10>,
  #    #<A:0x007fad7a0273b0 @user="Lois", @score=8>,
  #    #<A:0x007fad7a850b90 @user="Hubert", @score=7>, 
  #    #<A:0x007fad7a027310 @user="Billy-Bob", @score=6>,
  #    #<A:0x007fad7a027270 @user="Trixy", @score=4>,
  #    #<A:0x007fad7b876128 @user="Zelda", @score=2>]
insert_new(arr, A.new("Slim", 8))
  #    Slim is inserted between Hank and Lois
insert_new(arr, A.new("Rhonda", 8))
  #    Rhonda is inserted between Hank and Slim

Note

Notice that Zelda was inserted at the end. In that case,

arr.index { |instance| new_instance.score >= instance.score } #=> nil

so the index -1 was used (... || -1), meaning that the value is to be inserted after the last element of arr. See String#insert.

Upvotes: 3

Related Questions