2

If I have an array: array = ["ruby", "code", "library"]. How can I move matched /^library$/ elements to the beginning. So array will look like this: array = ["library", "ruby", "code"]

1
  • While I think Sean's answer is better you could use array.sort { |str| str.match(/^library$/) ? 0 : 1 } Commented Jun 24, 2016 at 18:50

4 Answers 4

5

it could be done in a number of ways. This is one

array = ["ruby", "code", "library"]
array.partition { |element| element.match /^library$/ }.flatten
Sign up to request clarification or add additional context in comments.

1 Comment

Enumerable#partition may preserve order, but the doc is mute on that.
2

Just out of curiosity:

[:select, :reject].map do |m|
  ["ruby", "code", "library"].public_send(m, &(/^library/.method(:=~)))
end.reduce :| 

4 Comments

that is quite an interesting way to go about it. Nice thought exercise :)
@Sean Yeah, this is more about ruby-golf jokes, than about real code. But as an exercise it is fine. Please revise, I updated it.
reduce :| made me laugh. Can we call that the "meh" operator?
@Jordan Yes, I pity that there are no :) and :] symbols permitted in Ruby :) “meh operator” is brilliant.
1
def move_to_front(arr, pattern)
  mi = matching_indices(arr, pattern)
  return arr unless mi
  a = arr.dup
  mi.reverse_each.with_object([]) { |i,b| b.unshift(a.delete_at(i)) }.concat(a)
end

def matching_indices(arr, pattern)
  arr.each_index.select do |i|
    case pattern
    when Regexp then arr[i] =~ pattern
    when Proc   then pattern[arr[i]]
    else             (arr[i] == pattern)
    end
  end
end

move_to_front ["ruby", "code", "library"], /\Alibrary\z/
  #=> ["library", "ruby", "code"]  
move_to_front ["ruby", "library", "code", "library"], "library"
  #=> ["library", "library", "ruby", "code"]  
move_to_front ["ruby", "libraries", "code", "library"], /librar(?:ies|y)/
  #=> ["libraries", "library", "ruby", "code"] 
move_to_front ["ruby", "libraries", "code", "library"], /\Alibrar/
  #=> ["libraries", "library", "ruby", "code"] 
move_to_front ["ruby", "libraries", "code", "library"],
  ->(str) { str =~ /librar(?:ies|y)/ }
  #=> ["libraries", "library", "ruby", "code"]
move_to_front ("1".."9").to_a, /[13579]/
  #=> ["1", "3", "5", "7", "9", "2", "4", "6", "8"] 
move_to_front ("1".."9").to_a, ->(n) { n.to_i.odd? }
  #=> ["1", "3", "5", "7", "9", "2", "4", "6", "8"] 
move_to_front ("1".."9").to_a, ->(n) { false }
  #=> ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
move_to_front ("1".."9").to_a, ->(n) { true }
  #=> ["1", "2", "3", "4", "5", "6", "7", "8", "9"]

Note:

matching_indices ["ruby", "libraries", "code", "library"], /librar(?:ies|y)/
  #=> [1, 3]

The method move_to_front preserves the order of those elements that are moved and those that are not moved.

Comments

0

Three for one cent.

array.inject([]){|a,e| e[/^library/] ? a.unshift(e) : a<<e}

and

array & ["library"] | array

In case array contains the search element multiple times it becomes

array.find_all{ |e| e[/^library/] } + array.reject{ |e| e[/^library/] }

If you hate to use the array variable twice it can also like this

[array].map{|a| a & ["library"] | a}.flatten

The last one: using grep

array.grep(/library/) + array.grep( /^(?!library)/)

3 Comments

The last one doesn't do what you think it does. /[^library]/ will match any string that contains a character other than l, i, b, etc. Perhaps you meant /^(?!library)/?
@Jordan, I was aware of that and /^(?!library)/ would be better I suppose but the thing is: it works because it lets pass other strings and not "library"
Sure, but it'll also match "lliibbrraarryy" and "yrarbil".

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.