2

sort_by_this_array = [4,2,1,3] <-- This is array of attribute goal_id.

& then I have my

[<Todo id: 12, goal_id: 2]>, <Todo id: 13, goal_id: 2>, <Todo id: 6, goal_id: 1>, <Todo id: 7, goal_id: 2 >, <Todo id: 25, goal_id: 3 >, <Todo id: 30, goal_id: 1 >, <Todo id: 40, goal_id: 4 >] 

Result should be: id: 40, 12,13,7, 6,30, 25

I'm thinking about 2 loops & it's definitely not the best way.

3
  • 1
    possible duplicate of Sorting an array of objects in Ruby by object attribute Commented Nov 8, 2013 at 3:58
  • Thank you for your reply. It looks like it sorting in ASC-ing order. sort_by(&:goal_id). I need a little bit different. I edited my question a little bit, may it become clearer. Commented Nov 8, 2013 at 4:18
  • sort_by_this_array = [4,2,1,3] First, take all goal_id = 4, then goal_id = 2, goal_id = 1 & goal_id = 3 Commented Nov 8, 2013 at 6:28

3 Answers 3

7

Maybe try this approach:

S = Struct.new(:id, :v)
a = Array.new(5) { |i| S.new(i, i) }
a.shuffle!
a.sort_by {|e| [2, 3 , 1 , 4, 0].index(e.id) }

It will return your a in order by ids.

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

Comments

1

You may want to use variation of sorting by selection where swapping would occur each time you find a 'todo' element for which its 'goal_id' attribute is equal to 'goal_id' from your array.

Todo = Struct.new(:id, :goal_id)
todos = [Todo.new(12,2), Todo.new(13,2),Todo.new(6,1), Todo.new(7,2), Todo.new(25,3), Todo.new(30,1), Todo.new(40,4)]
sort_by_this_array = [4,2,1,3]

j = 0
sort_by_this_array.each do |goal_id|
  todos.each_with_index do |todo,i|
    if todo.goal_id == goal_id
      todos[i],todos[j] = todos[j],todos[i]
      j += 1
    end
  end
end

I would reccommend reading some sources on the web about sorting by selection. As this is a simple variation of it http://www.sorting-algorithms.com/selection-sort

Unfortunately this solution will not preserve order of elements inside initial todos array, as each swapping changes the position on which todo element is located. So they will be sorted, but it will be not stable.

Below stable solution with additional memory.

j = 0
results = []
sort_by_this_array.each do |goal_id|
  while idx = todos.index {|e| e.goal_id == goal_id}
    results << todos[idx]
    todos.delete_at(idx)
  end
end

2 Comments

Thank you very much mate. Two loops :) I did it too with two loops, but after Igor Kasyanchuk's answer I'll ... :) Thank you guys for help.
You need to be aware that using a.sort_by {|e| [2, 3 , 1 , 4, 0].index(e.id) } will not preserve initial order as well as in some cases using sort_by may be just inefficient. For more information I would suggest reading information at following site: apidock.com/ruby/Enumerable/sort_by. Sometimes one liners aren't best option (in terms of performance), but it very depends on your use case.
0

You can try this:

Todo.all.sort_by{|e| e[:goal_id]}

Check this post

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.