1

Assuming I have an array or arrays:

arr = [["Foo1", "Bar1", "1", "W"],
       ["Foo2", "Bar2", "2", "X"],
       ["Foo3", "Bar3", "3", "Y"],
       ["Foo4", "Bar4", "4", "Z"],
       ["Foo5", "Bar5", "5", "A"]]

Is there a way I can move an individual array in the 2d array based on some criteria?

For example, if element 3 of the inner array is "4", then move it to the top?

So the above arr would then look like:

  [["Foo4", "Bar4", "4", "Z"],
   ["Foo1", "Bar1", "1", "W"],
   ["Foo2", "Bar2", "2", "X"],
   ["Foo3", "Bar3", "3", "Y"],
   ["Foo5", "Bar5", "5", "A"]]

I have tried things like to try and select the inner array:

arr.map {|row| row.select {|i| i[3] == "4"} }

3 Answers 3

2

You certainly can. Easiest way is to find the match first, and if it exists move it to the desired position.

index = arr.index{|i| i[2] == '4' }
arr.insert(0, arr.delete_at(index)) if index

Remember the indices in an array are 0 based, so you're looking at index 2 if you want to check the third element in the array.

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

4 Comments

Thanks for this. I may have been overthinking it
We've all been there!
You can use arr.unshift(element) instead of arr.insert(0, element)
You can and that would be better if moving it to the start of the array is required. The OP asked about moving it in general though so I thought I'd show that as it was more flexible.
0

Most generic way would be probably using Array#sort:

▶ criteria = ->(arr) { arr[2] == "4" }
#⇒ #<Proc:0x005570424c2568@(pry):8 (lambda)>
▶ arr.sort do |e1, e2|
▷   criteria.(e1) ? -1 : criteria.(e2) ? 1 : e1 <=> e2
▷ end
#⇒ [["Foo4", "Bar4", "4", "Z"],
#   ["Foo1", "Bar1", "1", "W"],
#   ["Foo2", "Bar2", "2", "X"],
#   ["Foo3", "Bar3", "3", "Y"],
#   ["Foo5", "Bar5", "5", "A"]]

That way you might update criteria as you want and everything will still work.


Or, more explicitly preserving the original order (credits to @StefanPochmann):

arr.sort_by.with_index { |e, i| [criteria[e] ? 0 : 1, i] }

2 Comments

The second way has the indexes still in the result. And how about sort_by? That even allows adding indexes as an afterthought that doesn't appear in the result: arr.sort_by.with_index { |e, i| [criteria[e] ? 0 : 1, i] }
@StefanPochmann indeed, thanks, updated, the original version was indeed a complete crap.
0

Just another way, also works if there's more than one inner array to be moved:

arr.partition { |e| e[2] == '4' }.sum([])

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.