2

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 :)

1

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Hey Cary, I don't know why you are being downvoted, but this is the best answer. The default -1 is really smart, haha. Thank you for the comprehensive example, too. Thanks for the effort! You really helped me out :)
2

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)

1 Comment

This is indeed a smart solution! The only problem here would be that if the new_user.score is always smaller than the other scores, it won't be inserted at the end like it should. Cary Swoveland gave a similar answer to yours and he added a default value of -1 if the foo.index returns nil. But this is definitely the right approach, I think! Thanks Rahul :)

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.